在实现了单链表的简单函数实现之后,在此基础上,我们可以实现链表的一部分扩展:
一、删除无头结点单链表的非尾结点
void EraseNotTail(pLinkNode pos);
既然是无头结点的链表,那么就不能考虑从头结点开始遍历找到这个结点时直接free。
我们可以换个思路考虑一下,将此结点的data值改为下一个结点的data值,而将下一个结点删除,这样,我们也可以得到同样的效果。分析如图:
代码如下:
void EraseNotTail(pLinkNode pos)//删除无头单链表的非尾结点
{
pLinkNode cur = NULL;
assert(pos->next);
cur = pos->next;
pos->data = pos->next->data;
pos->next = pos->next->next;
free(cur);
}
二、逆序链表
void ReverList(pLinkList pList);
逆序链表,首先,我们应该清楚这是一个单向链表,所以我们不可能定义两个结点指针分别指向链表的头和尾,然后每交换一次,一个指针向后移动,一个指针向前移动。因此,我们只能从前向后遍历。那么应该怎么做呢?!
我们可以利用“头插”的思想,请看图分析:
void ReverList(pLinkList pList)//逆序链表
{
pLinkNode cur = NULL;
pLinkNode tmp = NULL;
pLinkNode newHead = NULL;
assert(pList);
cur = pList->pHead;
while(cur)
{
tmp = cur;
cur = cur->next;
tmp->next = newHead;
newHead = tmp;
}
pList->pHead = newHead;
}
三、在指定结点位置前插入数据(无头结点)
void InsertFrontNode(pLinkNode pos,DataType x);
既然时无头结点的单向链表,我们可以参考第一题的思路。解决该问题,可以在pos位置后插入一个新的结点newnode,然后交换newnode->data和pos->data,就ok了!
分析如图:
代码如下:
void InsertFrontNode(pLinkNode pos,DataType x)//在当前结点前插入一个数据(无头结点单链表)
{
pLinkNode newnode = BuyNode(x);
DataType tmp = 0;
assert(pos->next != NULL);
newnode->next = pos->next;
pos->next = newnode;
tmp = pos->data;
pos->data = newnode->data;
newnode->data = tmp;
}
四、查找一个链表的中间结点
pLinkNode FindMiddleNode(pLinkList pList);
该问题可以利用快慢指针来解决,即:快指针每次走两步,慢指针每次走一步,那么快指针肯定先到达链表尾部的,当快指针遍历完链表停下来后,慢指针所指向的位置一定是链表的中间位置。
代码实现如下:
pLinkNode FindMiddleNode(pLinkList pList)//查找一个链表的中间节点
{
pLinkNode fast = NULL;
pLinkNode slow = NULL;
assert(pList);
fast = pList->pHead;
slow = pList->pHead;
while(fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}