線性表的鏈式存儲結構(C語言實現)


  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 */

 

運行截圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM