数据结构之单链表

单链表

好处:①无需一次性定制链表的容量;②插入和删除无需移动数据元素

坏处:①数据元素需要保存后继元素的位置信息;②获取数据元素操作需要顺序访问之前的元素

 

 链表头(表头节点):链表中的第一个节点,包含指向第一个数据元素的指针以及链表自身的一些信息(即链表长度length)

 数据节点:链表中的代表数据元素的节点,包含指向下一个数据元素的指针和数据元素的信息
 
 尾节点:链表中的最后一个数据节点,其下一元素指针为空,表示无后继
 
理解:
1 typedef struct Str_LinkList LinkListNode;  //这个结构体是链表的真身   
2 struct Str_LinkList   //每一个链表元素的结构都会包含这个结构  因为当给链表元素强制类型   
3 {                     //转换成(LinkListNode* )的时候  其实就是要开始对每个元素中的 LinkListNode进行赋值了   
4     LinkListNode* next;  
5 };

 

 
可以复用的单链表:
1、LinkList.c
  1 /******************************************************************************************************* 
  2 文件名:LinkList.c 
  3 头文件:LinkList.h  
  4 功能:  可以复用 带有增 删 改 查 功能的单链表 
  5 难点: 1.typedef struct Str_LinkList LinkListNode;  //这个结构体是链表的真身  
  6         struct Str_LinkList   //每一个链表元素的结构都会包含这个结构  因为当给链表元素强制类型  
  7         {                     //转换成(LinkListNode* )的时候  其实就是要开始对每个元素中的 LinkListNode进行赋值了  
  8             LinkListNode* next; 
  9         };  
 10         这个链表结构在链表元素中起到的作用 是本节的难点  
 11         2.切记一个问题  就是已经是链表中元素的 千万不要再往链表中添加了 否则链表一定出现无穷的错误  
 12         3.对于pos值的问题  add、get、del三个函数中 的链表都是 从1开始的到length  0是链表头  
 13                           在add函数中pos为0的时候是和pos为1的情况是一样的  都是头插法  0~~~~~无穷大  
 14                           在get函数中pos为0的时候是获得链表头 地址      0~~~~~length  
 15                           在del函数中pos为0的时候是无效的 del失败       1~~~~~length  
 16 *******************************************************************************************************/  
 17 #include <stdio.h>  
 18 #include <stdlib.h>  
 19 #include <malloc.h>  
 20 #include "LinkList.h"  
 21   
 22 typedef struct str_list_head  //这个是链表头 其实也可以当作一个没有前驱的 链表元素 元素的内容是链表长度   
 23 {  
 24     //LinkListNode* next;  
 25     LinkListNode head; //这个参数要特别重视 每一个链表元素结构的第一个参数一定是 LinkListNode  
 26                        //因为在寻找链表元素后继的时候 其实就是将链表元素强制类型转换成 LinkListNode*  然后给next进行赋值 其实就是给 LinkListNode变量赋值   
 27     int length; //链表长度   
 28 }list_head;  
 29   
 30 /******************************************************************************************************* 
 31 函数名: Creat_LinkListHead 
 32 函数功能:创建一个链表的链表头 并给链表头分配空间 
 33 参数: void 
 34 返回值:ret 成功返回链表头地址  失败返回NULL  
 35 *******************************************************************************************************/  
 36 LinkList* Creat_LinkListHead(void)  
 37 {  
 38     list_head* ret = NULL;  
 39     ret = (list_head* )malloc( sizeof(list_head)*1 );  
 40     if(NULL != ret) //malloc分配成功   
 41     {  
 42         ret -> length = 0;  
 43         //ret -> next = NULL;  
 44         ret -> head.next = NULL;  
 45     }  
 46     return (LinkList* )ret;   
 47 }  
 48   
 49 /******************************************************************************************************* 
 50 函数名:Destroy_LinkListHead 
 51 函数功能:释放一个链表头指针  
 52 参数:LinkList* head 链表头指针  
 53 返回值: ret 释放成功返回1  释放失败返回0  
 54 *******************************************************************************************************/  
 55 int Destroy_LinkListHead(LinkList* head)  
 56 {  
 57     int ret = 0;   
 58     list_head* lhead = (list_head* )head;  
 59     if( NULL != lhead )  
 60     {  
 61         free(lhead);  
 62         ret = 1;  
 63     }  
 64     return ret;  
 65 }  
 66   
 67 /******************************************************************************************************* 
 68 函数名:Get_Length 
 69 函数功能:获得链表的长度  
 70 参数: LinkList* head 链表头指针  
 71 返回值: ret 成功返回链表长度  失败返回0  
 72 *******************************************************************************************************/  
 73 int Get_Length(LinkList* head)   
 74 {  
 75     int ret = 0;  
 76     list_head* lhead = (list_head* )head;  
 77     if( NULL != lhead )  
 78     {  
 79         ret = lhead -> length;  
 80     }     
 81     return ret;  
 82 }  
 83   
 84 /******************************************************************************************************* 
 85 函数名:Clean_LinkListHead 
 86 函数功能:   清空链表  
 87 参数: LinkList* head 链表头指针  
 88 返回值:ret 成功返回1 失败返回0  
 89 *******************************************************************************************************/  
 90 int Clean_LinkListHead(LinkList* head)   
 91 {  
 92     int ret = 0;  
 93     list_head* lhead = (list_head* )head;  
 94     if( NULL != lhead )  
 95     {  
 96         lhead -> length = 0;  
 97         //lhead -> next = NULL;  
 98         lhead -> head.next = NULL;  
 99         ret = 1;  
100     }     
101     return ret;  
102 }  
103   
104 /******************************************************************************************************* 
105 函数名:Add_LinkList 
106 函数功能:往链表里面添加一个链表元素 如果pos的值是0(就是链表头)和1(链表的第一元素 链表元素个数是从1开始算的)都是头插法 
107           pos的值大于链表长度是尾插法  这里面pos值得注意的是 i=1 pos为a的时候 是把链表元素插入第a个元素的位置  
108           当i=0 pos为a的时候 是把链表元素插入 第a个元素位置的后面    切忌:这里面0位置是链表头指针 从1开始是链表元素  
109 参数:   LinkList* head链表头指针    LinkListNode* Node插入元素的指针(被强制类型转化成LinkListNode*)  int pos 插入位置  
110          pos的有效值范围是 从0到无穷大   
111 返回值: ret 插入成功返回1  插入失败返回0  
112 *******************************************************************************************************/  
113 int Add_LinkList(LinkList* head, LinkListNode* Node, int pos)  
114 {  
115     int ret = 0;  
116     int i = 0;  
117     list_head* lhead = (list_head* )head;  
118     LinkListNode* node = (LinkListNode* )head;  
119     ret=( NULL != node) && ( NULL != Node) && (pos >= 0);  
120     if(1 == ret)  
121     {  
122         for(i=1; ( (i<pos) && (node->next != NULL) ); i++)  
123         {  
124             node = node->next;  
125         }  
126         Node -> next = node -> next;  
127         node -> next = Node;  
128           
129         lhead -> length++;   
130     }  
131     return ret;  
132 }  
133   
134 /******************************************************************************************************* 
135 函数名:Get_LinkListNode 
136 函数功能:获得链表中第pos个元素位置的链表元素 链表是从1开始的  0是链表头   pos为0的时候表示get链表头  
137 参数: LinkList* head链表头指针    int pos获得链表元素的位置  pos的有效取值范围是 1 到  length  0是链表头  
138 返回值: LinkListNode*类型 第pos个链表元素的地址  
139 *******************************************************************************************************/  
140 LinkListNode* Get_LinkListNode(LinkList* head, int pos)  
141 {  
142     int ret = 0;  
143     int i = 0;  
144     list_head* lhead = (list_head* )head;  
145     ret=( NULL != lhead) && (pos >= 0) && (pos <= lhead->length);  
146     if(1 == ret)  
147     {  
148         LinkListNode* node = (LinkListNode* )head;  
149         for(i=0; i<pos; i++) //执行 pos次   得到的是第pos位置的node   
150         {  
151             node = node->next;  
152         }     
153         return (LinkListNode*)node;  
154     }  
155     return NULL;  
156 }  
157   
158 /******************************************************************************************************* 
159 函数名:Del_LinkListNode 
160 函数功能:删除链表中第pos位置的链表元素  
161 参数: LinkList* head链表头指针    int pos删除链表元素的位置  pos是删除的链表元素的位置 跟get和add中的 
162        pos是配套的  有效取值范围依然是 1到 length  在这个函数里面由于不能删除链表头 所以pos为0的时候无效  
163 返回值: LinkListNode* ret这个返回值很重要 因为这个删除仅仅是把链表元素踢出了链表 并没有free开辟的内存 
164          应该通过这个返回的地址free  释放内存 
165          删除成功返回 删除链表元素的地址   删除失败返回 NULL  
166 *******************************************************************************************************/  
167 LinkListNode* Del_LinkListNode(LinkList* head, int pos)  
168 {  
169     LinkListNode* ret = NULL;  
170     int i = 0;  
171     list_head* lhead = (list_head* )head;  
172     if(( NULL != lhead) && (pos > 0) && (pos <= lhead->length))  
173     {  
174         LinkListNode* node = (LinkListNode* )head;  
175         for(i=1; i<pos; i++)//执行 pos次   得到的是第pos位置的node  这个方法行不通   
176         {                   //因为要想删除第pos位置的node 应该先找到它上一个链表元素   
177             node = node->next; //所以这里面i=1 比get函数少执行了一次  得到第pos-1位置的node   
178         }  
179         ret = node->next;  
180         node->next = ret->next;     
181           
182         lhead->length--;  
183     }  
184     return (LinkListNode*)ret;  
185 }  

 

 2、LinkList_h

 1 #ifndef __LinkList_H__  
 2 #define __LinkList_H__  
 3   
 4 typedef void LinkList;  //这个是为了 封装方便   
 5 typedef struct Str_LinkList LinkListNode;  //这个结构体是链表的真身   
 6 struct Str_LinkList   //每一个链表元素的结构都会包含这个结构  因为当给链表元素强制类型   
 7 {                     //转换成(LinkListNode* )的时候  其实就是要开始对每个元素中的 LinkListNode进行赋值了   
 8     LinkListNode* next;  
 9 };  
10   
11 LinkList* Creat_LinkListHead(void);  
12   
13 int Destroy_LinkListHead(LinkList* head);  
14   
15 int Get_Length(LinkList* head);  
16   
17 int Clean_LinkListHead(LinkList* head);  
18   
19 int Add_LinkList(LinkList* head, LinkListNode* Node, int pos);  
20   
21 LinkListNode* Get_LinkListNode(LinkList* head, int pos);  
22   
23 LinkListNode* Del_LinkListNode(LinkList* head, int pos);   
24    
25 #endif 

 

 3、main.c
 1 #include <stdio.h>  
 2 #include <stdlib.h>  
 3 #include <malloc.h>  
 4 #include <string.h>  
 5 #include "LinkList.h"  
 6   
 7 typedef struct student  
 8 {  
 9     //LinkListNode* next;  
10     LinkListNode node;  
11     int num;  
12     char name[30];  
13 }str;  
14 int main(int argc, char *argv[])   
15 {  
16     str str1,str2,str3,str4,str5,str6,*strp;  
17     int i=0;  
18     LinkList* list_head;  
19     list_head = Creat_LinkListHead();  
20       
21     str1.num = 1;  
22     strcpy(str1.name,"haohao");  
23       
24     str2.num = 2;  
25     strcpy(str2.name,"ququ");  
26       
27     str3.num = 3;  
28     strcpy(str3.name,"popo");  
29       
30     str4.num = 4;  
31     strcpy(str4.name,"wowo");  
32       
33     str5.num = 5;  
34     strcpy(str5.name,"tiantian");  
35   
36     str6.num = 6;  
37     strcpy(str6.name,"cheche");  
38       
39     Add_LinkList(list_head, (LinkListNode*)&str1, 0);  
40     Add_LinkList(list_head, (LinkListNode*)&str2, 0);  
41     Add_LinkList(list_head, (LinkListNode*)&str3, 0);  
42     Add_LinkList(list_head, (LinkListNode*)&str4, 0);  
43     Add_LinkList(list_head, (LinkListNode*)&str5, 0);  
44     strp = (str*)Del_LinkListNode(list_head, 5);  
45     printf("%d\n",strp->num);  
46     printf("%s\n",strp->name);  
47     printf("\n");  
48     for(i=1; i<= Get_Length(list_head); i++)  
49     {  
50         strp = (str*)Get_LinkListNode(list_head, i);  
51         printf("%d\n",strp->num);  
52         printf("%s\n",strp->name);  
53     }   
54     printf("\n");  
55     Add_LinkList(list_head, (LinkListNode*)&str6, 3);     
56     for(i=1; i<= Get_Length(list_head); i++)  
57     {  
58         strp = (str*)Get_LinkListNode(list_head, i);  
59         printf("%d\n",strp->num);  
60         printf("%s\n",strp->name);  
61     }   
62           
63       
64     Clean_LinkListHead(list_head);  
65     Destroy_LinkListHead(list_head);  
66     return 0;  
67 }  

 

posted @ 2019-06-11 15:06  千小塔  阅读(245)  评论(0编辑  收藏  举报