构建一个单链表,链表中存储的是用户输入的整数
一、实现了以下功能:
- 链表初始化
- 链表判空
- 在指定结点之后添加结点
- 在指定结点之前添加结点(思路重要)
- 删除指定结点p
- 结点添加------首添&尾添
- 遍历并输出链表
- 查找链表的元素------按位序查找(封装起来,在List_Insert和List_DeleteByOrder这两个函数中调用)&按值查找
- 删除链表的元素------按值删除&按位删除
- 更改链表的指定元素
- 在链表的指定位置添加元素
- 在链表的指定位置添加元素(引入链表长度pList->size)
- 链表的清空
二、亮点:用自己定义的数据结构struct _list表示整个链表
该结构中存放了一个始终指向头结点的指针head,一个始终指向尾结点的指针tail,一个表示单链表长度的变量size
指针head和tail给链表的结点添加带来方便,不需要遍历整个链表(函数List_AddOnTail)
变量size给在链表指定位置添加结点带来方便,可以简化代码(函数List_Insert)
三、存在的问题(放在另一个随笔中):
在函数List_DeleteByValue中:链表中存在多个相同的元素相邻时,无法全部删除(重点是相邻,相同元素不相邻时均可删除)
只能删除第偶数个位置的元素
解决方法:
- 空间:将原来的链表进行拷贝(或者做一个辅助数组),对原来的链表进行判断,对备份链表进行删除操作(数据量太大时不推荐)
- 时间:不改动删除算法,用这个算法对这个链表进行多次操作,直到删除完为止
- 再加一个指针:prev,使用三指针方法解决
代码执行结果如下:
代码如下:
1 # include <stdio.h> 2 # include <stdlib.h> 3 # include <stdbool.h> 4 //定义结构体(结点) 5 typedef struct _node { 6 int value; 7 struct _node * next; 8 } Node; 9 10 //定义数据结构struct _list表示整个链表 11 //存放链表的信息:头结点(如果有的话)或首结点、尾结点、链表长度等等 12 typedef struct _list 13 { 14 Node* head;//始终指向首结点 15 Node* tail;//始终指向尾结点 16 int size;//表示链表的长度,用在List_Insert函数中,用来判断输入的位置i是否越界,可以简化代码 17 } List; 18 //初始化链表 19 bool InitList(List* pList) 20 { 21 pList->head = pList->tail = NULL; 22 pList->size = 0; 23 return true; 24 } 25 //判空 26 bool Empty(List* pList) 27 { 28 return (pList->head==NULL); 29 } 30 31 //在指定结点之后添加结点 32 bool InsertNextNode(Node* p, int elem) 33 { 34 bool sign = true; 35 if(p == NULL) 36 { 37 sign = false; 38 } 39 Node* s = (Node*)malloc(sizeof(Node)); 40 if(s == NULL)//内存分配失败 41 { 42 sign = true; 43 } 44 s->value = elem; 45 s->next = p->next; 46 p->next = s; 47 48 return sign; 49 } 50 //在指定节点之前添加结点 51 /* 52 偷天换日的操作! 53 指定结点的前驱结点是未知的,从头结点遍历的话时间复杂度高O(n) 54 虽然结点不能交换位置,但是结点中的数据可以交换位置[O(1)] 55 */ 56 bool InsertPriorNode(Node* p, int elem) 57 { 58 bool sign = true; 59 if(p == NULL) 60 { 61 sign = false; 62 } 63 Node* s = (Node*)malloc(sizeof(Node)); 64 if(s == NULL) 65 { 66 sign = false; 67 } 68 //连接 69 s->next = p->next; 70 p->next = s; 71 //下面两个语句是精髓 72 s->value = p->value;//将结点p中的元素复制到s中 73 p->value = elem;//p中元素替换为elem 74 75 return sign; 76 } 77 //删除指定结点p(局限:当该结点是尾结点时,无法完成操作) 78 bool DeleteNode(Node* p) 79 { 80 bool sign = true; 81 if(p == NULL) 82 { 83 sign = false; 84 } 85 Node* q = p->next;//q指向p的后继结点 86 p->value = p->next->value;//p结点和它的后继结点交换数据 87 p->next = q->next;//将q结点删除 88 free(q); 89 90 return sign; 91 } 92 //结点添加(尾添加) 93 Node* List_AddOnTail(List* pList, int number)//传入指针的指针 94 { 95 //分配结点空间,并写入p->value 96 Node* p = (Node*)malloc(sizeof(Node)); 97 p->value = number; 98 p->next = NULL; 99 //head始终指向首结点,tail始终指向尾结点 100 //如果链表是空的,最新分配的结点(p)既是head,也是tail 101 if(pList->head == NULL) 102 { 103 pList->head = p; 104 pList->tail = p; 105 } 106 //如果链表不是空的,只需要处理tail 107 else 108 { 109 pList->tail->next = p;//此时链表的尾结点要指向新分配的结点 110 pList->tail = p;//新分配的结点成为链表的tail 111 } 112 pList->size ++; 113 pList->tail->next = NULL;//tail里面的指针必须是NULL 114 115 /* //在链表的尾结点之后添加结点,需要循环, 116 Node* last = pList->head; 117 if(last) 118 { 119 while(last->next) 120 { 121 last = last->next; 122 } 123 //接上去 124 last->next = p; 125 } 126 else 127 { 128 pList->head = p; 129 } 130 */ 131 return pList->head; 132 } 133 //结点添加(头添) 134 Node* List_AddOnHead(List* pList, int n) 135 { 136 Node* p = (Node*)malloc(sizeof(Node)); 137 p->value = n; 138 p->next = NULL; 139 if(pList->head == NULL) 140 { 141 pList->head = p; 142 pList->tail = p; 143 } 144 else 145 { 146 p->next = pList->head; 147 pList->head = p; 148 } 149 pList->size ++; 150 return pList->head; 151 } 152 //遍历输出链表 153 void List_Print(List* pList) 154 { 155 Node* p; 156 for(p=pList->head; p; p=p->next) 157 { 158 printf("%-5d", p->value); 159 } 160 printf("\n"); 161 } 162 //查(按位) 163 Node* List_GetElem(List* pList, int i) 164 { 165 Node* q; 166 if(i<1 || i>pList->size) 167 q = NULL; 168 else 169 { 170 Node* p = pList->head; 171 int j = 1; 172 while(j<i) 173 { 174 p = p->next; 175 j++; 176 } 177 q = p; 178 } 179 180 return q; 181 } 182 //查(按值) 183 bool List_Search(List* pList, int number) 184 { 185 bool isFound = false; 186 Node* p; 187 for(p=pList->head; p; p=p->next) 188 { 189 if(p->value == number) 190 { 191 isFound = true; 192 break; 193 } 194 } 195 return isFound; 196 } 197 //按值删除元素(仅删除第一个) 198 void List_DeleteByValue(List* pList, int number) 199 { 200 Node* prev; 201 Node* p; 202 Node* q; 203 for(p=pList->head,q=NULL; p; q=p,p=p->next) 204 { 205 if(number == p->value) 206 { 207 if(q) 208 { 209 q->next = p->next; 210 } 211 else 212 { 213 pList->head = p->next; 214 } 215 free(p); 216 break; 217 } 218 } 219 } 220 //更改指定元素 221 void List_Change(List* pList, int a, int b) 222 { 223 Node* p; 224 for(p=pList->head; p; p=p->next) 225 { 226 if(p->value == a) 227 { 228 p->value = b; 229 } 230 } 231 } 232 //在指定位置添加元素,引入链表长度(pList->size) 233 bool List_Insert(List* pList, int i, int elem) 234 { 235 bool sign = true; 236 if(i<1 || i>pList->size+1) 237 sign = false; 238 else if(i == 1) 239 { 240 Node* s = (Node*)malloc(sizeof(Node)); 241 s->value = elem; 242 s->next = pList->head; 243 pList->head = s; 244 } 245 //找到第i-1个结点 246 else 247 { 248 Node* p = List_GetElem(pList, i-1);//封装 找到第i-1个结点,注意这里传入的参数是List*类型 249 sign = InsertNextNode(p,elem);//封装 在第i-1个结点之后插入新结点 250 } 251 return sign; 252 } 253 //按位序删除元素 254 bool List_DeleteByOrder(List* pList, int i, int* elem) 255 { 256 bool sign = true; 257 if(i<1 || i>pList->size+1) 258 sign = false; 259 else if(i == 1) 260 { 261 Node* p = pList->head; 262 pList->head = p->next; 263 free(p); 264 } 265 //找到第i-1个结点 266 else 267 { 268 Node* p = List_GetElem(pList, i-1);//简单的封装 注意这里传入的参数是List*类型 269 if(p==NULL || p->next==NULL)//i值越界或者第i-1个结点没有后继结点 270 { 271 sign = false; 272 } 273 Node* q = p->next; 274 *elem = q->value; 275 p->next = q->next; 276 free(q); 277 } 278 return sign; 279 } 280 //清除链表 281 bool List_Clear(List* pList) 282 { 283 Node* p; 284 Node* q; 285 bool sign = true; 286 if(pList->head == NULL) 287 sign = false; 288 p = pList->head->next; 289 while(p) 290 { 291 q = p->next; 292 free(p); 293 p = q; 294 } 295 pList->head->next = NULL;//注意!!!不能少 296 return sign; 297 } 298 299 int main(void) 300 { 301 //创建并初始化,输入元素 302 List list; 303 InitList(&list); 304 int number; 305 printf("请输入整数(输入-1结束):\n"); 306 do 307 { 308 scanf("%d", &number); 309 if(number != -1) 310 { 311 list.head = List_AddOnTail(&list, number);//注意这里要传入head的地址 312 //list.head = List_AddOnHead(&list, number); 313 } 314 }while(number != -1); 315 //遍历并输出链表 316 printf("链表中的元素为:"); 317 List_Print(&list); 318 //查(按值) 319 printf("\n请输入您要查找的元素:"); 320 scanf("%d", &number); 321 if(List_Search(&list, number) == true) 322 { 323 printf("找到了!\n"); 324 } 325 else 326 { 327 printf("没找到!\n"); 328 } 329 //查(按位) 330 printf("请输入您要查找的位序:"); 331 int i, elem; 332 scanf("%d", &i); 333 if(List_GetElem(&list, i) != NULL) 334 { 335 printf("找到了!该元素是%d\n", List_GetElem(&list, i)->value);//这个地方的写法有问题吗? 336 } 337 else 338 { 339 printf("位序越界!\n"); 340 } 341 //删除,按元素值 342 printf("\n请输入您要删除的元素:"); 343 scanf("%d", &number); 344 if(List_Search(&list, number) == true) 345 { 346 List_DeleteByValue(&list, number); 347 printf("删除成功!当前链表中的元素为:"); 348 List_Print(&list); 349 } 350 else 351 { 352 printf("删除失败!您要删除的元素不存在!\n"); 353 } 354 355 //更改链表元素 356 int a, b; 357 printf("\n请输入旧元素:"); 358 scanf("%d", &a); 359 if(List_Search(&list, a)) 360 { 361 printf("请输入新元素:"); 362 scanf("%d", &b); 363 List_Change(&list, a, b); 364 printf("更改成功!当前链表元素为:"); 365 List_Print(&list); 366 } 367 else 368 { 369 printf("未找到!\n"); 370 } 371 //插入元素 372 printf("\n请输入您要插入的位置和数字:"); 373 scanf("%d%d", &i, &elem); 374 if(List_Insert(&list, i, elem)) 375 { 376 printf("插入成功!当前链表元素为:"); 377 List_Print(&list); 378 } 379 else 380 { 381 printf("插入失败!\n"); 382 } 383 //按位序删除元素 384 printf("\n请输入您要删除的结点的位序:"); 385 scanf("%d", &i); 386 if(List_DeleteByOrder(&list, i, &elem)) 387 { 388 printf("删除成功!删除的元素为:%d\n当前链表元素为:", elem); 389 List_Print(&list); 390 } 391 else 392 { 393 printf("删除失败!\n"); 394 } 395 396 //链表清除 397 if(List_Clear(&list)) 398 { 399 printf("\n链表已清空!\n"); 400 } 401 else 402 { 403 printf("\n清空失败,链表为空\n"); 404 } 405 406 return 0; 407 }