1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define OK 1 5 #define ERR 2 6 #define TRUE 1 7 #define FALSE 0 8 9 typedef int status; //定義函數返回的狀態,OK & ERR 10 typedef char datatype; //定義線性表中每個結點的數據類型,這里暫定為字符型 11 12 typedef struct LinkList_anon{ 13 datatype data; //數據區 14 struct LinkList_anon * next; //指針區 15 } LinkList; 16 17 /* 函數原型,線性表的基本操作 */ 18 LinkList *createLinkList(datatype first_node_value); 19 status isEmpty(LinkList *L); 20 void clear(LinkList **L); 21 int getLength(LinkList *L); 22 int locateNode(LinkList *L,datatype node_to_locate); 23 datatype getNode(LinkList *L, int index); 24 status insert(LinkList **L, int index, datatype node_to_insert); 25 status delete(LinkList **L, int index); 26 void showList(LinkList *L); 27 28 int main(){ 29 /* 測試 */ 30 LinkList *root; //指向線性表 31 root=createLinkList('A'); //創建一個線性表 32 printf("Length = %d\n",getLength(root)); //打印線性表的當前長度 33 printf("isEmpty = %d\n",isEmpty(root)); //打印線性表是否為空 34 insert(&root,0,'B'); //頭插法插入2個結點 35 insert(&root,0,'C'); 36 printf("Length = %d\n",getLength(root)); 37 printf("isEmpty = %d\n",isEmpty(root)); 38 showList(root); 39 putchar('\n'); 40 insert(&root,getLength(root),'D'); //尾插法插入2個結點 41 insert(&root,getLength(root),'E'); //尾插法插入2個結點 42 printf("Length = %d\n",getLength(root)); 43 printf("isEmpty = %d\n",isEmpty(root)); 44 showList(root); 45 putchar('\n'); 46 insert(&root,1,'F'); //在index=1(第2個結點)插入新結點 47 insert(&root,2,'G'); //在index=2(第3個結點)插入新節點 48 insert(&root,2,'H'); //在index=2(第3個結點)插入新節點 49 printf("Length = %d\n",getLength(root)); 50 printf("isEmpty = %d\n",isEmpty(root)); 51 showList(root); //打印線性表 52 putchar('\n'); 53 delete(&root,0); //刪除頭結點 54 showList(root); 55 putchar('\n'); 56 delete(&root,getLength(root)-1); //刪除尾結點 57 showList(root); 58 putchar('\n'); 59 delete(&root,3); //刪除index=3(第4個)結點 60 showList(root); 61 putchar('\n'); 62 printf("Locate = %d\n",locateNode(root,'A')); //打印查找到的結點的位置 63 printf("getNode = %c\n",getNode(root,1)); //打印下標是1的結點的值 64 clear(&root); //清空線性表 65 printf("isEmpty = %d",isEmpty(root)); 66 67 return 0; 68 } 69 70 LinkList *createLinkList(datatype first_node_value){ 71 LinkList *tmp; 72 tmp=malloc(sizeof(LinkList));//void*類型指針能自動轉為其他類型的指針 73 tmp->data=first_node_value; //初始化頭指針的數據區 74 tmp->next=NULL; //初始化頭結點的指針區 75 return tmp; 76 } 77 status isEmpty(LinkList *L){ 78 if (L==NULL) 79 return TRUE; //鏈表為空返回TRUE 80 else 81 return FALSE; //鏈表不為空返回FALSE 82 } 83 void clear(LinkList **L){ 84 if (isEmpty(*L)==FALSE){ 85 //不為空時才執行刪除 86 LinkList * p,* q; //p始終指向當前要被刪除的結點,而q始終指向要被刪除的結點的下一個 87 p=*L; //將p指向線性表的頭結點 88 while (p!=NULL){ 89 //p不是NULL就繼續循環 90 q=p->next; //q始終指向下一個結點 91 free(p); //釋放p所指的結點 92 p=q; //交換 93 } 94 *L=NULL; //將指向線性表的指針設為NULL 95 } 96 } 97 int getLength(LinkList *L){ 98 int i=0; 99 LinkList * p=L; 100 if (isEmpty(L)==TRUE) return 0; 101 while (p){ 102 i++; 103 p=p->next; 104 } 105 return i; 106 } 107 int locateNode(LinkList *L, datatype node_to_locate){ 108 //返回找到的結點的index 109 //node_to_locate應當是能唯一標識一個結點的數據,否則只返回匹配的第一個結點 110 int i; 111 int total=getLength(L); 112 LinkList * p=L; 113 for (i=0; i<total; i++){ 114 if (p->data==node_to_locate) 115 return i; 116 else 117 p=p->next; 118 } 119 return -1; //未找到任何匹配 120 } 121 datatype getNode(LinkList *L, int index){ 122 //index表示線性表中第N個結點,頭結點的index是0 123 int i=0; //計數器 124 LinkList * p=L; //臨時結點,用於遍歷 125 if (isEmpty(L)==TRUE) return (datatype)ERR; //線性表為空 126 while (p!=NULL && i<index){ 127 //p不是NULL且i還沒等於index時,循環繼續 128 p=p->next; 129 i++; 130 } 131 return p->data; 132 } 133 status insert(LinkList **L, int index, datatype node_to_insert){ 134 //node_to_insert表示想要插入的結點 135 //當列表為空時,只有index=0才能插入 136 //當index=0時,即頭插,會修改傳入的指針,將其指向新的頭結點 137 //當index=getLength(root)時,即尾插 138 int k; 139 LinkList * p; 140 LinkList * tmp=malloc(sizeof(LinkList)); 141 if (index<0) return ERR; //index不在有效范圍 142 if (index==0){ 143 //頭插 144 tmp->next=*L; //將新結點的指針區指向鏈表的頭結點,隨之,新節點變成鏈表的頭結點 145 tmp->data=node_to_insert; //數據區 146 *L=tmp; //將原來指向頭結點的指針修改為現在的新頭結點 147 return OK; 148 } 149 if (index>getLength(*L)-1){ 150 //尾插 151 tmp->next=NULL; //因為是尾插,此結點是鏈表的最后一個結點,所以指針區為NULL 152 tmp->data=node_to_insert; //數據區 153 p=*L; //變量p用於遍歷 154 while (p){ 155 //尋找當前線性表的最后一個結點,用於將新結點附在它的后面 156 if (p->next==NULL) 157 //找到了當前鏈表的最后一個 158 break; 159 p=p->next; //繼續下一個結點 160 } 161 p->next=tmp; //將原來線性表的最后一個結點指向新的尾結點 162 return OK; 163 } 164 //不是頭插也不是尾插 165 k=0; 166 p=*L; 167 for (k=0; k<index-1; k++){ 168 //遍歷到第index個結點的前一個結點,頭結點的index等於0 169 //利用index的前一個結點的next就可以知道第index個結點 170 p=p->next; 171 } 172 tmp->next=p->next; //把tmp接到index前面 173 p->next=tmp; //再把tmp接到index前一個結點的后面 174 tmp->data=node_to_insert; //數據區 175 return OK; 176 } 177 status delete(LinkList **L, int index){ 178 //當index=0時,即頭刪 179 //當index=getLength(root)-1時,即尾刪 180 int k; 181 LinkList * p,* q; 182 if (index<0) return ERR; //index不在有效范圍 183 if (index==0){ 184 //頭刪 185 p=(*L)->next; //先將原來的頭結點的下一個結點的指針保存起來 186 free(*L); //釋放原來的頭結點 187 *L=p; //將原來指向頭結點的指針修改為現在的新頭結點 188 return OK; 189 } 190 if (index>getLength(*L)-2){ 191 //尾刪 192 p=*L; //變量p用於遍歷 193 while (p){ 194 //尋找當前線性表的最后一個結點的前一個結點,將這個結點的后一個結點(即最后一個結點)刪除 195 if (p->next->next==NULL) 196 //找到 197 break; 198 p=p->next; //繼續下一個結點 199 } 200 free(p->next); //將原來線性表的最后一個結點刪除 201 p->next=NULL; //將原來的倒數第二個結點變成尾結點 202 return OK; 203 } 204 //不是頭插也不是尾插 205 p=*L; 206 for (k=0; k<index-1; k++){ 207 //遍歷到第index個結點的前一個結點,頭結點的index等於0 208 //利用index的前一個結點的next就可以知道第index個結點 209 p=p->next; 210 } 211 q=p->next; 212 p->next=p->next->next; //將index前一個結點和后一個結點相連 213 free(q); //刪除index的結點 214 return OK; 215 } 216 void showList(LinkList *L){ 217 int i; 218 int total=getLength(L); 219 LinkList * p=L; 220 for (i=0; i<total; i++){ 221 printf("%c\t",p->data); p=p->next; 222 } 223 } 224 225 /* 226 鏈式存儲結構的線性表的優缺點:(注意,上述實現的鏈式線性表叫做單鏈表) 227 優點: 228 1.插入和刪除的時間復雜度是0(1) 229 2.存儲空間不受預設限制 230 缺點: 231 1.尋找某個結點需要進行遍歷操作 232 另外, 233 把單鏈表的尾結點的指針區指向頭結點,便成為循環鏈表; 234 把單鏈表的每個結點再增加一個指針區,新加的指針區指向前一個結點,便成為雙向鏈表 235 */ 236 /* 環境: Code::Blocks with GCC 5.1 */
運行截圖: