C语言初级链表(之有头节点的单向链表)
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <stdlib.h> 4
5 6 typedef struct Node 7 { 8 int data; 9 struct Node *next; 10 }SLIST; 11 12 13 //创建链表 14 SLIST *Slist_create() 15 { 16 SLIST *pHead, *pM, *pCur; //申请链表的辅助指针变量 17 int data; //数据域的接收 18 19 //创建头节点并初始化 20 pHead = (SLIST *)malloc(sizeof(SLIST)); 21 if (NULL == pHead) 22 return NULL; 23 pHead->data = 0; 24 pHead->next = NULL; 25 26 //提示输入内容 27 printf("plz input the data \n"); 28 scanf("%d", &data); 29 30 //对当前结点进行定位 31 pCur = pHead; 32 33 //循环创建业务节点 34 while (data != -1) 35 { 36 //创建业务节点实际操作、然后初始化 37 pM = ((SLIST *)malloc(sizeof(SLIST))); 38 if (NULL == pM) 39 return NULL; 40 pM->data = data; 41 pM->next = NULL; 42 43 //业务节点入链表 44 pCur->next = pM; 45 46 //当前节点下移 47 pCur = pM; 48 49 //提示输入内容 50 printf("plz input the data \n"); 51 scanf("%d", &data); 52 53 } 54 55 return pHead; 56 } 57 58 59 //打印链表 60 int Slist_printf(SLIST *pHead) //形参接收头节点地址 61 { 62 SLIST *tap = NULL; //创建临时指针变量 63 if (NULL == pHead) 64 return -1; 65 67 //临时指针变量初始化 :第一个节点 68 tap = pHead->next; 69 70 printf("\nSTART\n"); 71 while (tap) 72 { 73 //打印当前结点数据域的内容 74 printf("%d ", tap->data); 75 76 //临时指针变量下移 77 tap = tap->next; 78 } 79 printf("END\n"); 80 return 0; 81 } 82 83 //在链表中某一位置插入元素 84 int Slist_NodeInsert(SLIST *pHead, int x, int y) 85 { 86 //创建辅助指针变量 87 SLIST *pPre, *pCur, *pM; 88 89 //前驱结点初始化 90 pPre = pHead; 91 //当前结点初始化 92 pCur = pHead->next; 93 //创建插入节点 94 pM = (SLIST *)malloc(sizeof(SLIST)); 95 //插入节点初始化 96 pM->next = NULL; 97 //数据域为要插入的值 98 pM->data = y; 99 //遍历链表 100 while (pCur) 101 { 102 //判断元素节点,如果是跳出循环 103 if (pCur->data == x) 104 break; 105 //指针下移 106 pPre = pCur; 107 pCur = pCur->next; 108 109 } 110 //插入节点入链表:分为两种情况,①找到要插入的节点插入在当前位置②未找到要插入的节点,插入在链表尾部 111 pM->next = pPre->next; 112 pPre->next = pM; 113 return 0; 114 } 115 116 //删除链表节点 117 int Slist_NodeDel(SLIST *pHead, int y) 118 { 119 //创建辅助指针变量 120 SLIST *pPre, *pCur; 121 //指针变量初始化 122 pPre = pHead; 123 pCur = pHead->next; 124 125 //遍历链表 126 while (pCur) 127 { 128 //判断是否找到要删除的链表节点;如果是则跳出循环 129 if (pCur->data == y) 130 break; 131 132 //指针下移 133 pPre = pCur; 134 pCur = pCur->next; 135 } 136 //判断是否找到要删除的链表节点:未找到 137 if (pCur == NULL) 138 { 139 printf("未找到要删除的节点\n"); 140 return -1; 141 } 142 //找到要删除的链表节点 143 pPre->next = pCur->next; 144 //这段判断语句的作用是:判断链表是否存在 145 if (pPre == NULL) 146 free(pCur); //释放当前节点内存(即要删除节点的内存) 147 return 0; 148 } 149 150 //链表逆置 151 int Slist_Reverse(SLIST *pHead) 152 { 153 //创建指针变量 154 SLIST *pPre, *pCur, *tap; 155 //判断是否需要逆置:(当链表元素>=2时才可以逆置) 156 if (pHead == NULL || pHead->next == NULL || pHead->next->next == NULL) 157 return -1; 158 //初始化指针变量 159 pPre = pHead->next; 160 pCur = pHead->next->next; 161 //遍历链表 162 while (pCur) 163 { 164 //缓存当前结点的指针域 165 tap = pCur->next; 166 //对当前结点的指针域重新赋值为前驱结点; 即逆置 167 pCur->next = pPre; //(这里有做错:写成pCur->next = pPre-next) 168 //指针下移 169 pPre = pCur; 170 pCur = tap; 171 } 172 173 //对头节点和第一个元素的指针域进行处理 174 pHead->next->next = NULL; 175 pHead->next = pPre; 176 177 return 0; 178 } 179 180 //销毁链表 181 int Slist_Destory(SLIST *pHead) 182 { 183 //创建辅助指针变量 184 SLIST *tap; 185 186 //判断链表是否存在 187 if (pHead == NULL) 188 return -1; 189 //遍历链表 190 while (pHead) 191 { 192 //缓存当前节点的指针域 193 tap = pHead->next; 194 //释放当前结点 195 free(pHead); 196 //指针下移 197 pHead = tap; 198 } 199 return 0; 200 } 201 202 203 int main(void) 204 { 205 int ret = 0; 206 SLIST *pHead = NULL; 207 208 //创建链表 209 pHead = Slist_create(); 210 ret = Slist_printf(pHead); 211 //给链表中插入元素 212 ret = Slist_NodeInsert(pHead, 20, 19); 213 ret = Slist_printf(pHead); 214 //删除链表中某个元素 215 ret = Slist_NodeDel(pHead, 19); 216 ret = Slist_printf(pHead); 217 //重置链表中的元素 218 ret = Slist_Reverse(pHead); 219 ret = Slist_printf(pHead); 220 //销毁链表 221 ret = Slist_Destory(pHead); 222 223 return 0; 224 225 }
1.结构体的基本特点:(结构体中可以嵌套一个别的结构体; ..........可以嵌套一个别的结构体指针)
(结构体中不可以嵌套一个自身类型的结构体(原因:确定不了结构体的内存大小);
..........可以嵌套一个指向自身类型的指针(原因:不同类型的指针在同一操作平台下所占内存相同,有确定值)
2.数据类型的本质:固定大小的内存块别名。
3.链表的基础特点:(结构体; 两个域:数据域、指针域; 引用自身的结构体; 特点:非线性存储)
4.链表编程关键两点:
1)指针指向谁,就把谁的地址赋给指针
2)辅助指针变量&操作逻辑的关系(辅助指针:pHead(头节点) pPre(前驱结点) pCur(当前结点) pM(业务节点))
=========================================================
此段代码刚开始是: 两个文件.C 和 一个.h文件,传代码由于不方便放到一个.C文件。
编写这段代码时,最难理解的是辅助节点的建立和移动。
编写错误的:167 pCur->next = pPre;(正确写法)
pCur->next = pPre->next;(错误写法:这种写法造成对第二元素的循环打印,死循环。)
63 if (NULL == pHead);(正确写法)
if (NULL == tap); (错误写法:这种写法造成程序崩溃;)。
路之遥