嵌入式数据结构笔记三——单向链表下
文章目录
- 前言
- 一、查找链表中间节点:
- 二、查找链表倒数第k个节点:
- 三、不知道头结点地址删除链表中间节点:
- 四、链表的倒置:
- 五、链表的排序:
- 1.冒泡排序:
- 2.选择排序:
- 六、判断链表是否有环:
- 七、Makefile:
- 重点
前言
数组要求内存空间必须连续,链表通过指针操作离散的元素,能高效利用内存中的零碎空间。并以“空间换时间”的方式,实现了高效的插入与删除操作。
正文内容:
一、查找链表中间节点:
- 快指针每次走2步,慢指针每次都1步
- 快指针走到末尾,慢指针走到中间
/* 查找链表中间节点 */
linknode *find_midnode(linknode *phead)
{linknode *pslow = NULL;linknode *pfast = NULL;pslow = pfast = phead->pnext;while (pfast != NULL){pfast = pfast->pnext;if (NULL == pfast){break;}pfast = pfast->pnext;if (NULL == pfast){break;}pslow = pslow->pnext;}return pslow;
}
二、查找链表倒数第k个节点:
- 快指针先走k步
- 慢指针和快指针每次走一步
- 快指针到达末尾,慢指针少走k步,即倒数第k个元素
/* 查找链表倒数第k个节点 */
linknode *find_last_kth_node(linknode *phead, int k)
{linknode *pfast = NULL;linknode *pslow = NULL;pfast = phead->pnext;pslow = phead->pnext;int i = 0;for (i = 0; i < k; i++){if(NULL == pfast){return NULL;}pfast = pfast->pnext;}while (pfast != NULL){pfast = pfast->pnext;pslow = pslow->pnext;}return pslow;
}
三、不知道头结点地址删除链表中间节点:
- 将指针指向的下一个节点的值覆盖当前节点的值
- 删除下一个节点
/* 删除指定节点 */
int delete_linknode(linknode *ptmpnode)
{linknode *pnextnode = NULL;pnextnode = ptmpnode->pnext;ptmpnode->data = pnextnode->data;ptmpnode->pnext = pnextnode->pnext;free(pnextnode);pnextnode = NULL; //局部变量也可以不赋return 0;
}
四、链表的倒置:
将链表中的所有元素倒置
- 将原链表断开
- 将所有的元素依次使用头插法插入
/* 链表倒置 */
int reverse_linklist(linknode *phead)
{linknode *pinsertnode = NULL;linknode *ptmpnode = NULL;//将链表从头结点处断开ptmpnode = phead->pnext;phead->pnext = NULL;//依次将所有元素使用头插法插入链表中while (ptmpnode != NULL){pinsertnode = ptmpnode;ptmpnode = ptmpnode->pnext;pinsertnode->pnext = phead->pnext;phead->pnext = pinsertnode;//如果写成pinsertnode->pnext = NULL;则在第二次循环时会断掉}return 0;
}
五、链表的排序:
1.冒泡排序:
- 采用冒泡排序思想,定义两个指针,相邻两个元素比较
- 指针循环向后走,直到ptmpnode2为NULL,即等于pend,循环停止
- pend赋值为tmpnode1的节点地址
- 下一轮就可以少比1次
- 循环将所有大的元素找到,剩余一个小的元素即可
/* 链表的冒泡排序 */
int bubble_sort_linklist(linknode *phead)
{linknode *ptmpnode1 = NULL;linknode *ptmpnode2 = NULL;linknode *pend = NULL;datatype tmpdata;if (NULL == phead->pnext || NULL == phead->pnext->pnext ){return 0;}while (1){ptmpnode1 = phead->pnext;ptmpnode2 = phead->pnext->pnext;if (pend == ptmpnode2) //如果ptmpnode2和pend的起始位置一致就无须再比了{break;}while (ptmpnode2 != pend){if (ptmpnode1->data > ptmpnode2->data){tmpdata = ptmpnode1->data;ptmpnode1->data = ptmpnode2->data;ptmpnode2->data = tmpdata;}ptmpnode1 = ptmpnode1->pnext;ptmpnode2 = ptmpnode2->pnext;}pend = ptmpnode1;}return 0;
}
2.选择排序:
- pswapnode指向要交换的节点
- pminnode假设的最小值
- ptmpnode和后续节点比较
/* 链表的选择排序 */
int select_sort_linklist(linknode *phead)
{linknode *pswapnode = NULL;linknode *ptmpnode = NULL;linknode *pminnode = NULL;datatype tmpdata;if (NULL == phead->pnext || NULL == phead->pnext->pnext){return 0;}pswapnode = phead->pnext;while (pswapnode->pnext != NULL){pminnode = pswapnode;ptmpnode = pswapnode->pnext;while (ptmpnode != NULL){if (ptmpnode->data < pminnode->data){pminnode = ptmpnode;}ptmpnode = ptmpnode->pnext;}if (pswapnode != pminnode){tmpdata = pswapnode->data;pswapnode->data = pminnode->data;pminnode->data = tmpdata;}pswapnode = pswapnode->pnext;}return 0;
}
六、判断链表是否有环:
- 链表是否有环:
- 定义两个指针:快指针(每次走2步)和慢指针(每次走1步)
- 快指针 - 慢指针 == 环长 即相遇,快指针和慢指针相等即为链表有环
- 计算环长:
- 定义一个指针从环相遇点开始走一圈,直到走到该节点为止
- 每走一个节点计数,最终可得到环长
- 获得环的入口位置:
- 需要公式推导:
x:起始点到环入口的距离
y:环入口到相遇点的距离
z:相遇点到环入口的距离
pslow:x + y
pfast: x + y + n (y + z)
2 * (x + y) = x + y + n (y + z)
x + y = n (y + z)
x = n (y + z) - y
x= (n - 1) (y + z) + z——>当 n = 1 时 x = z - 定义一个指针从相遇点开始每次走一步,定义一个指针从开头每次走一步
- 两个指针相遇的位置即为环入口位置
- 需要公式推导:
/* 1.判断链表是否有环2.计算环长3.找到环的入口位置
*/
int circle_linklist(linknode *phead, int *pis_circle, int *pcirlen, linknode
**ppnode)
{linknode *pfast = NULL;linknode *pslow = NULL;linknode *ptmpnode = NULL;linknode *pstartnode = NULL;/* 判断是否有环 */pfast = phead->pnext;pslow = phead->pnext;while (1){pfast = pfast->pnext;if (NULL == pfast){break;}pfast = pfast->pnext;if (NULL == pfast){break;}pslow = pslow->pnext;if (pfast == pslow){break;}}if (NULL == pfast){*pis_circle = 0;return 0;}else{*pis_circle = 1;}/* 统计环长 */int cnt = 1;ptmpnode = pslow->pnext;while (ptmpnode != pslow){cnt++;ptmpnode = ptmpnode->pnext;}*pcirlen = cnt;/* 找到环入口 */pstartnode = phead->pnext;ptmpnode = pslow;while (pstartnode != ptmpnode){pstartnode = pstartnode->pnext;ptmpnode = ptmpnode->pnext;}*ppnode = ptmpnode;return 0;
}
七、Makefile:
a.out:linklist.c main.c gcc linklist.c main.c -g.PHONY:
memcheck://执行 make memcheck 时,会运行 valgrindvalgrind --tool=memcheck --leak-check=full ./a.out
clean://执行 make clean 时,会删除 a.out 文件rm a.out
重点
- 查找链表倒数第k个节点
- 链表的倒置
- 冒泡排序
- 环形链表