线性表的链式存储结构(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
",getLength(root)); //打印线性表的当前长度
 33     printf("isEmpty = %d
",isEmpty(root)); //打印线性表是否为空
 34     insert(&root,0,'B'); //头插法插入2个结点
 35     insert(&root,0,'C');
 36     printf("Length = %d
",getLength(root));
 37     printf("isEmpty = %d
",isEmpty(root));
 38     showList(root);
 39     putchar('
');
 40     insert(&root,getLength(root),'D'); //尾插法插入2个结点
 41     insert(&root,getLength(root),'E'); //尾插法插入2个结点
 42     printf("Length = %d
",getLength(root));
 43     printf("isEmpty = %d
",isEmpty(root));
 44     showList(root);
 45     putchar('
');
 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
",getLength(root));
 50     printf("isEmpty = %d
",isEmpty(root));
 51     showList(root); //打印线性表
 52     putchar('
');
 53     delete(&root,0); //删除头结点
 54     showList(root);
 55     putchar('
');
 56     delete(&root,getLength(root)-1); //删除尾结点
 57     showList(root);
 58     putchar('
');
 59     delete(&root,3); //删除index=3(第4个)结点
 60     showList(root);
 61     putchar('
');
 62     printf("Locate = %d
",locateNode(root,'A')); //打印查找到的结点的位置
 63     printf("getNode = %c
",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	",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 */

运行截图:

原文地址:https://www.cnblogs.com/ryzz/p/12215331.html