直接上代碼吧
#include<stdio.h> #include<malloc.h> /* 單鏈表特點: 它是一種動態的儲存結構,鏈表中每個節點占用的儲存空間不是預先分配的,而是運行時系統根據需求生成的 */ typedef struct lnode { int data; struct lnode *next; }lnode,*linklist; //結點定義 /* 關於頭指針的一點說明: linklist L; 外面用頭指針來標識一個單鏈表,如單鏈表L,單鏈表H等,是指鏈表的第一個節點的地址被記錄在指針變量L,H中,頭指針為NULL 時,表示一個空的單鏈表,需要進一步指出的是:上面定義的lnode是節點的類型,linklist是指向lnode節點的指針的類型, 為了增強程序的可讀性,通常將標識一個鏈表的頭指針說明為linklist類型的變量 */ linklist creat_linklist_insert_head_nohead() { linklist l=NULL;//定義頭指針變量l lnode *s;//新建一個節點 int flag=-1;//輸入停止標志位 printf("輸入整型數據,數據以空格隔開,輸入數據為-1的時候表示輸入截止\n"); while(1) { int x; scanf("%d",&x); if(x==flag) break; s=(lnode*)malloc(sizeof(lnode));//對s節點申請儲存空間 s->data=x;//賦值 s->next=l;//s節點的next指向頭指針 l=s;//頭指針指向新建立的s節點,因為這是在單鏈表的頭部插入數據 } return l; }//創建一個單鏈表,通過在頭部插入數據,不含空的頭節點 //-------------------------------------------------------------------------------------------------------------// /*在單鏈表的表頭插入,只要x!=flag,就是一直申請s結點,從而可以一直在表頭插入, 其中l=s是最重要的,因為這是將s插入到l的表頭,因為是在頭部插入,所以只要一個頭指針就可以, 若是在單鏈表的尾部插入,那么就需要尾部指針 關於此函數使用的一點說明: 我們輸入數據 1 2 3 4 5的時候,輸出的是 5 4 3 2 1,因為我們是在頭部插入數據的 */ //-------------------------------------------------------------------------------------------------------------// linklist creat_linklist_insert_end_yeshead() { linklist l=NULL,r=NULL;//定義頭指針變量和尾指針變量 lnode *s;//定義新建節點 int flag=-1;//輸入結束標志位 printf("輸入整型數據,數據以空格隔開,輸入數據為-1的時候表示輸入截止\n"); while(1) { int x; scanf("%d",&x); if(x==flag)//輸入數據等於輸入結束標志位則跳出循環 break; s=(lnode*)malloc(sizeof(lnode));//申請內存空間 s->data=x;//賦值 if(l==NULL)//單鏈表為空 l=s;//則將頭指針指向新建節點 else r->next=s;//不空的話則將尾指針的next指向s,因為如果不空的話,尾指針指向的肯定是一個數據節點,尾指針的next指向s是為了將兩個數據節點連接起來 r=s;//尾指針移動到新插入的節點上 } if(r!=NULL)//有數據 r->next=NULL;//尾指針的next指向空,說明尾指針后面沒有數據了,目的的為了保證單鏈表尾指針邏輯的合理性 return l; }//建立單鏈表且在鏈表尾部插入數據,含空的頭節點 //-----------------------------------------------------------------------------------------------------------------------// /*在單鏈表的尾部插入,只要沒有輸入結束的標志,就一直申請s結點,然后把x賦給s結點的data域, l=s是為了第一個結點的結點的處理,因為在此之前l是一個空表,然后因為不斷有新的結點生成,所以就是不斷把新的s結點賦給r的next, 這樣就不斷有s結點加入到了單鏈表中間,然后最重要的是每次新的結點加入到單鏈表中后要把r尾指針向后面移動,就是文中的r=s; 關於此函數的一點說明: 輸入數據 1 2 3 4 5,輸出還是 1 2 3 4 5,而不是 5 4 3 2 1,因為我們插入數據是在鏈表尾部插入的 */ //-----------------------------------------------------------------------------------------------------------------------// int length_linklist_yeshead(linklist l) { linklist p=l; int j=1; while(p->next) { j++; p=p->next; } return j; }//求單鏈表的表長,針對含有空的頭節點的單鏈表 int length_linklist_nohead(linklist l) { lnode *p=l; int j=0; while(p) { j++; p=p->next; } return j; }//求鏈表的表長,針對不含空的頭節點的單鏈表 lnode *get_linklist(linklist l,int i) { lnode *p=l; int j=0; while(p!=NULL&&j<i) { p=p->next; j++; } if(j==i) return p; else return NULL; }//單鏈表的查找第i個元素結點,*p=l就是使p指針指向l鏈表; lnode *locate_linklist(linklist l,int x) { lnode *p=l->next;//l為頭節點 while(p!=NULL&&p->data!=x) p=p->next; return p; }//單鏈表查找值為x的結點,找到后返回指向這個結點的指針;以后時刻要記得l為頭指針,因為定義了頭指針比沒有定義頭指針要方便許多; int insert_linklist(linklist l,int i,int x) { lnode *p,*s; p=get_linklist(l,i-1);//找到第i-1個結點 if(p==NULL) {printf("i錯誤");return 0;} else s=(lnode*)malloc(sizeof(lnode)); s->data=x; s->next=p->next; p->next=s; return 1; }//單鏈表的第i個結點后面的插入,重要的是申請,封裝s結點, int del_linklist(linklist l,int i) { i--; linklist p,s; p=get_linklist(l,i-1); if(p==NULL) { printf("該i-1節點不存在"); return -1; } else if(p->next==NULL) { printf("第i個結點不存在"); return 0; } else { s=p->next; p->next=s->next; free(s); return 1; } }//單鏈表中刪除第i個結點,那么就先要找到i個結點的前驅,也就是第i-1個結點,同理單鏈表中的插入也要知道其前驅結點,所以單鏈表中的頭節點的重要性就可想而知了 void printf_linklist(lnode *plisthead) { lnode *ptemp=plisthead; while(ptemp) { printf("%d\t",ptemp->data); ptemp=ptemp->next; } printf("\n"); }//鏈表打印函數 int main() { /* linklist l=creat_linklist_insert_end_yeshead(); printf("%d\n",length_linklist_yeshead(l)); insert_linklist(l,2,100);//第二個結點的后面插入100 printf_linklist(l); del_linklist(l,4);//刪除第四個結點 printf_linklist(l); */ /* linklist l=creat_linklist_insert_head_nohead(); printf("%d\n",length_linklist_nohead(l)); insert_linklist(l,2,100); printf_linklist(l); del_linklist(l,4); printf_linklist(l); */ return 0; }
