你退學吧小明!

k1ling發表於2020-11-07

ps1:最近資料結構上機各種程式設計題太難頂了 為了總結一下自己犯的憨批錯誤以及方便以後複習 開了個資料結構專欄 準備把這幾次上機和平常寫程式碼的一些東西記錄下來 我的程式設計水平比CTF還菜 各位湊合看 (看吐了我也沒辦法
歡迎來到憨批小明系列 jlu的老師們就喜歡給一系列zz操作的主人公起名叫小明 就離譜

小明打字(實現insert delete home end)

先上題

在這裡插入圖片描述

題目分析

這個題的難點有二
1.insert鍵功能實現 鍵盤insert的功能是從當前游標的下一個字元開始,對字元逐一進行替換,當替換到隊尾後若繼續輸入則相當於在隊尾新增
2.執行時間限制25ms 其實還是挺短的 而保證不超時的方法 學名叫降低時間複雜度 如果僅僅從時間層面考慮的話,說白了就是 儘量減少遍歷,迴圈等操作,或者多考慮迴圈退出的條件,再或者儘量少在主函式外實現函式減少函式呼叫 總而言之耗時多的操作越少越好 所以這時候儲存字串的資料結構選擇就很關鍵 基本上就是陣列和連結串列 根據函式操作和功能實現確定合適的資料結構 比如此題 考慮到題目中有刪除字元的操作 正常的陣列刪除之後從下一項到結尾角標都會發生變化 相當於遍歷 因此陣列大概率超時 而單連結串列雖然縮短了刪除時的操作但是題目中還有將游標左移和右移的操作 單連結串列只有一個指標一般來說只能滿足左移或右移之中的一個 而要實現另一個操作也十分複雜 因此也不適合 所以對於這道題來說最合適的是雙向連結串列

我使用的是雙向迴圈連結串列 即將頭和尾連線起來
(其實是懶得寫尾指標)

演算法設計思路

上流程圖~
在這裡插入圖片描述大體思路就是這樣 總的來說將操作符與字元分開識別然後對應進行相應操作

具體實現程式碼

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 struct hpxm{
 	char data;
 	struct hpxm *next;
 	struct hpxm *per;
 };
 struct hpxm *head,*now,*p;
 int main(){
 	int change=0;//判斷是否為第一個資料 
 	int flag=0;//判斷是插入還是替換 
 	char xm[50050];
 	gets(xm);
 	int lenth=strlen(xm);
 	int i;
 	head=(struct hpxm*)malloc(sizeof(struct hpxm));
 	head->next=NULL;
 	head->per=NULL;
 	now=head;
 	for(i=0;i<lenth;i++){
 		if((xm[i]>='a'&&xm[i]<='z') || xm[i]==' '){
 			if(flag==0){//常規模式 
 				if(change==0){//第一個節點 
 					struct hpxm *insert=(struct hpxm*)malloc(sizeof(struct hpxm));
 			     	insert->data=xm[i];
 			     	insert->next=head;
 			     	head->per=insert;
 			     	now->next=insert;
 			     	insert->per=now;
 			     	now=insert;
 			     	change=1;
				 }
				 else{//插入節點 
				     struct hpxm *insert=(struct hpxm*)malloc(sizeof(struct hpxm));
 			         insert->data=xm[i];
 			         insert->next=now->next;
 			         now->next->per=insert;
 			         now->next=insert;
 			         insert->per=now;
 			         now=insert;
 			    }
 		    }
 		    else{
 		    	
 		    	if(now->next==head){//替換模式但是在隊尾相當於加入新元素 
 		    		struct hpxm *insert=(struct hpxm*)malloc(sizeof(struct hpxm));
 			     	insert->data=xm[i];
 			     	insert->next=head;
 			     	head->per=insert;
 			     	now->next=insert;
 			     	insert->per=now;
 			     	now=insert;
 		    	}
				else{//加入新元素 
				 	now=now->next;
 		    	    p=now;
 		    	    struct hpxm *insert=(struct hpxm*)malloc(sizeof(struct hpxm));
 		    	    insert->data=xm[i];
 		    	    insert->next=now->next;
 		    	    now->next->per=insert;
 		    	    insert->per=now->per;
 		    	    now->per->next=insert;
 		    	    now=insert;
 		    	    free(p);
				}
 		     }
	    }
		 else{
		 	if(xm[i]=='['){//左側頭節點 
		 		now=head;
			 }
			 else{
			 	if(xm[i]==']'){//右側頭結點[1]
                    if(now==head){
                        continue;
                    }
                    else{
                        now=head->per;
                    }
			 		
				 }
				 else{
				 	if(xm[i]=='{'){//左移 
				 		if(now==head) continue;//頭部無法左移 
				 		else{ 
				 			now=now->per;
						 }
					 }
					 else{
					 	if(xm[i]=='}'){//右移 
					 		if(now->next==head) continue;//頭部無法右移 
					 		else{
					 			now=now->next;
							 }
						 }
						 else{
						 	if(xm[i]=='='){//刪除 
						 		p=now;
						 		now->per->next=now->next;
						 		now->next->per=now->per;
						 		if(now->next==head){//已經到了隊尾 
						 			now=now->per;
								 }
								 else{ 
								 	now=now->next;
								 }
						 		free(p);
							 }
							 else{
							 	if(xm[i]=='-'){//替換 
							 		flag=1-flag;
							 		continue;
							 	}
							 	else{
							 		continue;
									 }
								 }
							 }
						 }
					 }
				 }
			 }
		 }
		 p=head->next;
		 while(p!=head){
		 	printf("%c",p->data);
		 	p=p->next;
		 }
	    return 0;
	 }
	 
 
 

說明:
[1] 由於我使用了雙向迴圈連結串列 所以無論是頭和尾都會和頭結點之間存在關係 因此需要對當前游標的位置進行判斷 如果只有一個頭結點的話head->per初始化為NULL 此時如果執行end操作相當於讓游標指向NULL 而呼叫或者使用不存在的東西pta會識別為段錯誤

相關文章