1.鏈表
鏈表是線性表的一種,由一系列節點(結點)組成,每個節點包含一個數據域和一個指向下一個節點的指針域。鏈表結構可以克服數組需要預先知道數據大小的缺點,而且插入和刪除元素很方便,但是失去數組隨機讀取的優點。鏈表有很多種不同類型:單向鏈表,雙向鏈表和循環鏈表。
在鏈表中第一個節點叫頭節點(如果有頭節點)頭節點不存放有效信息,是爲了方便鏈表的刪除和插入操作,第一個有效節點叫首節點,最後一個節點叫尾節點。
2.單鏈表的操作
鏈表的操作一般有創建鏈表,插入節點,刪除節點,遍歷鏈表。插入節點的方法有頭插法和尾插法,頭插法是在頭部插入,尾插法是在尾部插入。
下面以一個帶頭節點,採用尾插法的鏈表說明鏈表的各種操作。
1 #include<stdio.h> 2 #include<stdlib.h> 3 //單鏈表 4 5 6 //節點結構體 7 typedef struct node 8 { 9 int value;//數據域 10 struct node*next;//指針域 11 }Node; 12 13 Node*createList();//創建鏈表並且返回頭節點指針 14 void deleteNode(Node*head);//刪除節點 15 void insertNode(Node*head);//插入節點 16 void travelList(Node*head);//遍歷鏈表 17 18 int main() 19 { 20 Node*head=createList(); 21 travelList(head); 22 insertNode(head); 23 travelList(head); 24 deleteNode(head); 25 travelList(head); 26 return 0; 27 } 28 //創建鏈表,返回頭節點指針 29 Node*createList() 30 { 31 //採用尾插法 32 Node*head;//頭節點 33 Node*tail;//尾節點 34 Node*temp=NULL; 35 int i,value,size; 36 head=(Node*)malloc(sizeof(Node));//頭節點 37 head->value=0; 38 head->next=NULL; 39 tail=head; 40 printf("輸入節點個數: "); 41 scanf("%d",&size); 42 printf("輸入各個節點的值: "); 43 44 for(i=0;i<size;i++) 45 { 46 scanf("%d",&value); 47 temp=(Node*)malloc(sizeof(Node)); 48 temp->value=value; 49 tail->next=temp;//讓尾節點的指針域指向新創建的節點 50 tail=temp;//尾節點改爲新創建的節點 51 tail->next=NULL;//讓尾節點的指針域爲空 52 } 53 return head; 54 } 55 //遍歷鏈表 56 void travelList(Node*head) 57 { 58 while(head->next!=NULL) 59 { 60 printf("%d\n",head->next->value); 61 head=head->next; 62 } 63 } 64 //插入節點 65 void insertNode(Node*head) 66 { 67 int value; 68 int position; 69 int pos=0; 70 Node*pre=NULL;//用來保存要插入節點的前一個節點 71 Node*newNode; 72 printf("輸入要插入節點的值: "); 73 scanf("%d",&value); 74 printf("要插入的位置: "); 75 scanf("%d",&position); 76 while(head!=NULL) 77 { 78 pos++; 79 pre=head; 80 head=head->next; 81 if(pos==position) 82 { 83 newNode=(Node*)malloc(sizeof(Node)); 84 newNode->value=value; 85 newNode->next=pre->next; 86 pre->next=newNode; 87 } 88 } 89 } 90 //刪除節點 91 void deleteNode(Node*head) 92 { 93 int value; 94 Node*pre=head; 95 Node*current=head->next; 96 printf("輸入要刪除節點的值: "); 97 scanf("%d",&value); 98 while(current!=NULL) 99 { 100 if(current->value==value) 101 { 102 pre->next=current->next; 103 free(current);//釋放空間 104 break; 105 } 106 pre=current; 107 current=current->next; 108 } 109 }
3.循環鏈表
循環鏈表就是讓尾節點的指針域不再是NULL,而是指向頭節點從而形成一個環。循環鏈表與單鏈表的操作沒有多少差別,只是判斷鏈表是否空應該是
tail->next==head。
4.雙向鏈表
雙向鏈表的每一個節點都有兩個指針域,一個前驅指針,指向前一個節點,頭節點的前驅指針爲NULL,一個後繼指針,指向後一個節點,尾節點的後繼指針爲NULL。雙向鏈表可以從任一個節點開始訪問到前後節點,不像單鏈表只能向前。代碼如下。
1 #include<stdio.h> 2 #include<stdlib.h> 3 //雙向鏈表 4 typedef struct node 5 { 6 int value;//數據域 7 struct node* lNext;//前驅指針 8 struct node* rNext;//後繼指針 9 }Node; 10 11 Node*createList();//創建鏈表並且返回頭節點指針 12 void deleteNode(Node*head);//刪除節點 13 void insertNode(Node*head);//插入節點 14 void travelList(Node*head);//遍歷鏈表 15 16 int main() 17 { 18 19 Node*head=createList(); 20 travelList(head); 21 insertNode(head); 22 travelList(head); 23 deleteNode(head); 24 travelList(head); 25 return 0; 26 } 27 28 Node*createList() 29 { 30 Node*head,*tail,*temp; 31 int num,value,i; 32 head=(Node*)malloc(sizeof(Node));//頭節點 33 head->value=0; 34 head->lNext=NULL; 35 head->rNext=NULL; 36 tail=head; 37 printf("輸入節點個數: "); 38 scanf("%d",&num); 39 printf("輸入各個節點的值: "); 40 for(i=0;i<num;i++) 41 { 42 scanf("%d",&value); 43 temp=(Node*)malloc(sizeof(Node)); 44 temp->value=value; 45 temp->lNext=tail; 46 tail->rNext=temp; 47 tail=temp; 48 tail->rNext=NULL; 49 } 50 return head; 51 } 52 53 54 void deleteNode(Node*head)//刪除節點 55 { 56 57 int value; 58 Node*pre; 59 Node*current=head->rNext; 60 printf("輸入要刪除節點的值: "); 61 scanf("%d",&value); 62 pre=head; 63 while(current!=NULL) 64 { 65 if(current->value==value) 66 { 67 pre->rNext=current->rNext;//上一個節點指向下一個節點 68 current->rNext->lNext=pre;//下一個節點的前驅指針指向上一個節點 69 free(current);//刪除該節點 70 } 71 pre=current; 72 current=current->rNext; 73 } 74 } 75 76 void insertNode(Node*head)//插入節點 77 { 78 Node*pre,*temp; 79 int value,pos; 80 int num=0; 81 printf("輸入要插入的值: "); 82 scanf("%d",&value); 83 printf("輸入要插入的位置: "); 84 scanf("%d",&pos); 85 while(head!=NULL) 86 { 87 num++; 88 pre=head;//保存上一個節點 89 head=head->rNext;//當前節點 90 if(pos==num) 91 { 92 temp=(Node*)malloc(sizeof(Node)); 93 temp->value=value; 94 temp->lNext=pre; 95 temp->rNext=head; 96 head->lNext=temp; 97 pre->rNext=temp; 98 } 99 } 100 } 101 102 void travelList(Node*head)//遍歷鏈表 103 { 104 while(head->rNext!=NULL) 105 { 106 printf("%d\n",head->rNext->value); 107 head=head->rNext; 108 } 109 }
其實只要弄懂單鏈表,其他也很簡單的,無論鏈表多複雜,本質還是操作指針的指向,想想就會明白了。
如果鏈表不會,後面的各種各樣的樹結構,就更不用學了。