15.单向链表的一些基本操作实现
Posted 喵小喵~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了15.单向链表的一些基本操作实现相关的知识,希望对你有一定的参考价值。
- 运行截图:
-
链表快速排序原理:
-
- 链表定义
struct LinkNode { int data; struct LinkNode *pNext; }; typedef struct LinkNode node;
- 尾部添加节点
void addback(node **phead, int data) { //先创建新的结点 node *pnew = (node *)malloc(sizeof(node)); pnew->data = data; pnew->pNext = NULL; //如果头结点为空 if (*phead == NULL) { //头结点指向pnew *phead = pnew; } else { //否则备份首地址,找到最后一个 node *ptemp = *phead; while (ptemp->pNext != NULL) { ptemp = ptemp->pNext; } ptemp->pNext = pnew; } }
- 显示链表
1 void showall(node *phead) 2 { 3 if (phead == NULL) 4 { 5 return; 6 } 7 else 8 { 9 printf("%5d 本节点地址:%p 下一个节点地址:%p\\n", phead->data, phead, phead->pNext); 10 showall(phead->pNext);//跳到下一个节点 11 } 12 }
- 反转显示
void revshowall(node *phead) { if (phead == NULL) { return; } else { showall(phead->pNext);//跳到下一个节点 printf("%d ,%p,%p\\n", phead->data, phead, phead->pNext); } }
- 头部插入
1 void addhead(node **pphead, int data) 2 { 3 node *pnew = (node *)malloc(sizeof(node)); 4 pnew->data = data; 5 pnew->pNext = NULL;//赋值 6 7 if (*pphead==NULL) 8 { 9 *pphead = pnew; 10 } 11 else 12 { 13 pnew->pNext = *pphead; 14 *pphead = pnew; 15 } 16 }
- 寻找第一个指定元素的位置
1 node *searchfirst(node *phead, int finddata) 2 { 3 for (node *p = phead; p != NULL; p = p->pNext) 4 { 5 if (p->data == finddata) 6 { 7 return p;//返回找到的地址 8 } 9 } 10 return NULL; 11 }
- 改变第一个指定元素的值
1 void changefirst(node *phead, int finddata,int newdata) 2 { 3 for (node *p = phead; p != NULL; p = p->pNext) 4 { 5 if (p->data == finddata) 6 { 7 p->data = newdata; 8 } 9 } 10 }
- 删除第一个指定元素
1 void deleteFirst(node **phead, int finddata) 2 { 3 node *p1 = NULL, *p2 = NULL;//p1向前,p2保存p1的上一个位置 4 p1 = *phead;//保存头结点 5 while (p1 != NULL) 6 { 7 if (p1->data != finddata) 8 { 9 p2 = p1; 10 p1 = p1->pNext; 11 } 12 else 13 { 14 break; 15 } 16 } 17 18 if (p1 == NULL) 19 { 20 return; 21 } 22 //如果是头结点 23 if (p1 == *phead) 24 { 25 *phead = (*phead)->pNext; 26 free(p1);//头部删除 27 } 28 else 29 { 30 p2->pNext = p1->pNext; 31 free(p1); 32 } 33 34 }
- 插入元素(在找到的元素之前插入)
1 void insertFirstHead(node **phead, int finddata,int newdata) 2 { 3 node *p1 = NULL, *p2 = NULL;//p1向前,p2保存p1的上一个位置 4 p1 = *phead;//保存头结点 5 while (p1 != NULL) 6 { 7 if (p1->data != finddata) 8 { 9 p2 = p1; 10 p1 = p1->pNext; 11 } 12 else 13 { 14 break; 15 } 16 } 17 18 if (p1 == NULL) 19 { 20 return; 21 } 22 23 24 node *pnew = (node *)malloc(sizeof(node));//新的结点 25 pnew->data = newdata; 26 pnew->pNext = NULL;//赋值 27 28 //如果是头结点 29 if (p1 == *phead) 30 { 31 pnew->pNext = p1; 32 *phead = pnew; 33 } 34 else 35 { 36 p2->pNext = pnew; 37 pnew->pNext = p1; 38 } 39 }
- 插入元素(在找到的元素之后插入)
1 void insertFirstBack(node **phead, int finddata, int newdata) 2 { 3 node *p1 = NULL, *p2 = NULL;//p1向前,p2保存p1的上一个位置 4 p1 = *phead;//保存头结点 5 while (p1 != NULL) 6 { 7 if (p1->data != finddata) 8 { 9 p2 = p1; 10 p1 = p1->pNext; 11 } 12 else 13 { 14 break; 15 } 16 } 17 18 if (p1 == NULL) 19 { 20 return; 21 } 22 23 //创建新的结点 24 node *pnew = (node *)malloc(sizeof(node)); 25 pnew->data = newdata; 26 pnew->pNext = NULL;//赋值 27 28 //如果是头结点 29 if (p1 == *phead) 30 { 31 p1->pNext = pnew; 32 } 33 else 34 { 35 pnew->pNext = p1->pNext; 36 p1->pNext = pnew; 37 } 38 }
- 链表冒泡排序
1 void bubblesort(node *phead) 2 { 3 for (node *p1 = phead; p1->pNext != NULL; p1 = p1->pNext) 4 { 5 for (node *p2 = phead; p2 ->pNext != NULL; p2 = p2->pNext) 6 { 7 8 if (p2->data > p2->pNext->data) 9 { 10 int tmp = p2->data; 11 p2->data = p2->pNext->data; 12 p2->pNext->data = tmp; 13 } 14 } 15 } 16 }
- 链表分段,返回中间点,用于递归快速排序链表
1 node *fen(node *pbegin, node *pback) 2 { 3 int key = pbegin->data;//以第一个数据为分段 4 //核心思想:保证p,q直接的数据都大于等于key,q在p的后面 5 node *p = pbegin;//标识第一个节点 6 node *q = pbegin->pNext;//游标标识第二个节点 7 8 while (q != pback) 9 { 10 //找到小于key的数据,然后交换 11 if (q->data < key) 12 { 13 //循环下一个节点,并进行赋值(p,q之间的值都大于key) 14 p = p->pNext; 15 16 int temp = p->data; 17 p->data = q->data; 18 q->data = temp;//交换 19 } 20 q = q->pNext;//循环游标 21 } 22 int temp = p->data; 23 p->data = pbegin->data; 24 pbegin->data = temp;//交换 25 26 return p; 27 }
- 快速排序
1 void quicksort(node *pbegin,node *pback) 2 { 3 if (pbegin != pback) 4 { 5 node *pfen = fen(pbegin, pback);//取中间点 6 quicksort(pbegin, pfen); 7 quicksort(pfen->pNext, pback); 8 } 9 }
- 获取链表的长度
1 int getnum(node *phead) 2 { 3 int i = 0; 4 while (phead != NULL) 5 { 6 i++; 7 phead = phead->pNext; 8 } 9 return i; 10 }
- 链表反转
1 void rewind(node **phead) 2 { 3 4 //备份头节点的地址 位置关系:front back tail 5 node *front = *phead; 6 //back在from的后面 7 node *back = (*phead)->pNext; 8 //反转后头结点的pNext为NULL 9 (*phead)->pNext = NULL; 10 //当后一个不为尾节点 11 while ( back != NULL) 12 { 13 //back节点的后一个节点,用于给back节点赋值 14 node *tail = back->pNext; 15 //back节点的pNext为front 16 back->pNext = front; 17 //front移到back节点位置 18 front = back; 19 back = tail;//back移到tail节点位置 20 } 21 *phead = front; 22 }
- 递归反转
1 node *digui_rew(node *phead) 2 { 3 //在结尾处返回 4 if (phead == NULL || (phead)->pNext == NULL) 5 { 6 return phead; 7 } 8 else 9 { 10 node *next = phead->pNext; 11 node *head = digui_rew(next); 12 next->pNext = phead; 13 phead->pNext = NULL; 14 15 //第一步递归返回 16 return head; 17 } 18 }
- 判断链表是否有环(追击相遇,一个一次前进一个,一个一次前进两个,如果有环则一定能相遇)
1 int isCir(node *phead) 2 { 3 node *p1 = phead;//一次前进一个 4 node *p2 = phead;//一次前进两个 5 6 int flag = 0;//0表示没有环 7 while (p1 != NULL && p2 != NULL && p2->pNext != NULL) 8 { 9 p1 = p1->pNext; 10 p2 = p2->pNext->pNext; 11 if (p1 == p2) 12 { 13 flag = 1; 14 break; 15 } 16 } 17 18 return flag; 19 }
- 有序链表合并,把link2合并到link1
1 void merge(node **head1, node **head2) 2 { 3 //备份head2的头结点地址,一直循环结束 4 node *p2 = *head2; 5 while (p2 != NULL) 6 { 7 //如果比头节点的值要小,则把p2变成p1的头结点 8 if (p2->data < (*head1)->data) 9 { 10 node *p2tmp = p2->pNext;//备份p2后一个元素 11 //把头结点地址*head1传给p2->pNext 12 p2->pNext = *head1; 13 //p2的地址传给*head1 14 *head1 = p2; 15 //向后遍历 16 p2 = p2tmp; 17 } 18 else 19 { 20 //p1是第一个后面的节点的data大于p2->data的节点,核心思想是把P2插入到p1之后 21 node *p1; 22 node *p2tmp = p2->pNext;//备份p2后一个元素 23 for (p1 = *head1; p1->pNext != NULL; p1 = p1->pNext) 24 { 25 if (p1->pNext->data > p2->data) 26 { 27 break; 28 } 29 } 30 p2->pNext = p1->pNext; 31 p1->pNext = p2; 32 33 p2 = p2tmp; 34 } 35 } 36 }
- 链表取中间值
1 node *findmid(node *phead) 2 { 3 if (isCir(phead)) 4 { 5 return NULL; 6 } 7 8 node *p1 = phead; 9 node *p2 = phead; 10 while (p1 != NULL && p2 != NULL && p2->pNext != NULL) 11 { 12 p1 = p1->pNext; 13 p2 = p2->pNext->pNext; 14 } 15 return p1; 16 }
完整代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 struct LinkNode 5 { 6 int data; 7 struct LinkNode *pNext; 8 }; 9 typedef struct LinkNode node; 10 11 //尾部添加节点 12 void addback(node **phead, int data); 13 //头部插入 14 void addhead(node **pphead, int data); 15 //显示链表 16 void showall(node *phead); 17 //反转显示 18 void revshowall(node *phead); 19 //寻找第一个元素的位置 20 node *searchfirst(node *phead, int finddata); 21 //改变第一个元素的值 22 void changefirst(node *phead, int finddata, int newdata); 23 //删除第一个元素 24 void deleteFirst(node **phead, int finddata); 25 //插入元素(在找到的元素之前插入) 26 void insertFirstHead(node **phead, int finddata, int newdata); 27 //插入元素(在找到的元素之后插入) 28 void insertFirstBack(node **phead, int finddata, int newdata); 29 //链表冒泡排序 30 void bubblesort(node *phead); 31 //快速排序 32 void quicksort(node *pbegin, node *pback); 33 //链表分段,返回中间点 34 node *fen(node *pbegin, node *pback); 35 //获取链表的长度 36 int getnum(node *phead); 37 //链表反转 38 void rewind(node **phead); 39 //递归反转 40 void digui_rew(node **phead); 41 //有序链表合并,把link2合并到link1 42 void merge(node **link1, node **link2); 43 //链表取中间值 44 node *findmid(node *phead); 45 46 //尾部添加节点 47 void addback(node **phead, int data) 48 { 49 //先创建新的结点 50 node *pnew = (node *)malloc(sizeof(node)); 51 pnew->data = data; 52 pnew->pNext = NULL; 53 54 //如果头结点为空 55 if (*phead == NULL) 56 { 57 //头结点指向pnew 58 *phead = pnew; 59 } 60 else 61 { 62 //否则备份首地址,找到最后一个 63 node *ptemp = *phead; 64 while (ptemp->pNext != NULL) 65 { 66 ptemp = ptemp->pNext; 67 } 68 ptemp->pNext = pnew; 69 } 70 71 72 } 73 74 //显示链表 75 void showall(node *phead) 76 { 77 if (phead == NULL) 78 { 79 return; 80 } 81 else 82 { 83 printf("%5d 本节点地址:%p 下一个节点地址:%p\\n", phead->data, phead, phead->pNext); 84 showall(phead->pNext);//跳到下一个节点 85 } 86 } 87 88 //反转显示 89 void revshowall(node *phead) 90 { 91 if (phead == NULL) 92 { 93 return; 94 } 95 else 96 { 97 showall(phead->pNext);//跳到下一个节点 98 printf("%d ,%p,%p\\n", phead->data, phead, phead->pNext); 99 } 100 } 101 102 //头部插入 103以上是关于15.单向链表的一些基本操作实现的主要内容,如果未能解决你的问题,请参考以下文章