链表面试题
基于上一次写的链表,现在,我们来讨论下面这些问题。1.链表的冒泡排序2.删除无头非尾节点3.反转链表4.在当前节点前插入一个数据x5.查找链表的中间节点。6.删除单链表的倒数第K个节点(K>1&&K<总长度)对于上面这6个问题,我们进行分析与解答。链表的代码我都已经写过博客:数据结构—单链表的实现另外,我也在我的github上有链表的代码
基于上一次写的链表,现在,我们来讨论下面这些问题。
1.链表的冒泡排序
2.删除无头非尾节点
3.反转链表
4.在当前节点前插入一个数据x
5.查找链表的中间节点。
6.删除单链表的倒数第K个节点(K>1&&K<总长度)
对于上面这6个问题,我们进行分析与解答。
链表的代码我都已经写过博客:数据结构—单链表的实现
另外,我也在我的github上有链表的代码,github链接
如还有什么问题,可以发邮件到 953659912@qq.com
1.链表的冒泡排序
关于链表的排序问题是我们需要关心的,链表的排序,排序时比较方便的就是交换链表所保存的内容,所以接下来我们来提供一种思路来解决这个问题。
在这里我们的思路是先有两个指针,一个头指针,一个尾指针,第一次从头进行冒泡到尾,第二次从头冒泡到最后一个节点的前一个节点,就这样一次进行下去,一直到冒泡到第一个节点和第二个节点。
讲到这,我想大家应该明白了怎么实现了吧。
下面附上代码实现过程。
void BubbleSort(pLinkList pList)
{
pLinkNode cur = NULL;
pLinkNode tail = NULL;
assert(pList);
cur = pList->pHead;
if ((pList->pHead == NULL)||(pList->pHead->next==NULL))
{
return;
}
while (cur != tail) //当尾指针不等于头指针时进行冒泡
{
while (cur->next != tail) //控制cur指针最后到的位置是倒数第二个节点
{
if (cur->data > cur->next->data)
{
datatype tmp = cur->data;
cur->data = cur->next->data;
cur->next->data = tmp;
}
cur = cur->next;
}
tail = cur;
cur = pList->pHead;
}
}
2.删除无头非尾节点
删除无头非尾的节点,我想乍一看大家可能会觉得没有什么思路,按照惯性思维,咱们删除一个节点的时候,应该对这个节点的前一个节点记住,然后让前一个系欸但指向删除节点的下一个节点,但是在这里我们说了已经是无头的节点。所以我们需要转换我们的思路,进行一种新的操作。
其实思路也挺简单的,就是我们要把删除的节点后的节点的数据放到要删除的节点上,删除了删除的节点后的节点,然后让删除节点指向删除删除的节点后的节点后的节点。
是不是感觉头都大了?
接下来,我用图解为大家分析下。
代码实现如下:
void EraseNotTail(pLinkNode pos)
{
pLinkNode del = NULL;
assert(pos->next != NULL); //断言,排除尾节点的情况
pos->data = pos->next->data; //让当前节点后面节点的数据赋给当前节点。
del = pos->next; //删除记录当前节点后的节点
pos->next = pos->next->next; //当前节点的nex指向删除节点的下一个节点。
free(del);
del = NULL;
}
3.反转链表
反转链表这个算法的实现也需要有一个清晰的思路,闲话就不多说了,咱们进入正题。对于反转链表,其实就是你把链表重新排下序。
void Reverse(pLinkList plist)
{
pLinkNode tmp = NULL; //记录中间节点
pLinkNode cur = NULL; //记录链表的第一个节点
pLinkNode newnode = NULL; //记录翻转后的第一个节点
assert(plist);
cur = plist->pHead;
while (cur != NULL)
{
tmp = cur; //
cur = cur->next;
tmp->next = newnode;
newnode = tmp;
}
plist->pHead = newnode;
}
4.在当前节点前插入一个数据x
在当前节点之前插入一个数据,按照常规思路坑定也是不行的,这时候我们就要像删除无头节点一样有一个思维:
我们可以把插入节点的数据放到新节点上,把新节点的数据放到插入节点的数据上。
这样我们就可以实现在当前节点前插入一个节点了。
void InsertFrontNode(pLinkNode pos, datatype x)
{
pLinkNode newnode = NULL;
assert(pos);
newnode = (pLinkNode)malloc(sizeof(LinkNode));
if (NULL == newnode)
{
printf("out of memory");
exit(EXIT_FAILURE);
}
newnode->data = pos->data;
pos->data = x;
newnode->next = pos->next;
pos->next = newnode;
}
5.查找链表的中间节点。
查找链表的中间节点,所采用的思路就是我们平时所说的快慢指针。
给一个快指针,让快指针每次移动两步,给一个慢指针,让慢指针每次移动一步,最后结果就是快指针移动到最后一个节点,慢指针最后移动到了中间的节点上。
pLinkNode FindMidNode(pLinkList pList)
{
pLinkNode fast = NULL;
pLinkNode slow = NULL;
assert(pList);
slow = fast = pList->pHead;
while (fast != NULL)
{
if (fast->next != NULL)
{
fast = fast->next->next;
}
else
{
break;;
}
slow = slow->next;
}
return slow;
}
6.删除单链表的倒数第K个节点(K>1&&K<总长度)
在这里,对于删除单链表的倒数第K个节点,我们采用的思路是首先给个front指针和back指针,让front指针移动K次,然后让front指针和back指针同时移动,一直到front指针指向为NULL,此时back指针指向的就是倒数第K个节点,然后我们就可以删除back节点,注意,这里所采用的删除的方法要和上面类似,采用交换删除的方式。
当然,在这里面请你考虑一些异常的情况!
void DelKNode(pLinkList pList, int k)
{
pLinkNode front = NULL;
pLinkNode back = NULL;
pLinkNode del = NULL;
assert(pList);
if (pList->pHead == NULL)
{
printf("链表为空!!\n");
return;
}
if (k == 1)
{
printf("K应当大于1\n");
return;
}
front = back = pList->pHead;
while (front != NULL)
{
k--;
if (k < 0)
{
back = back->next;
}
front = front->next;
}
if (k <= 0)
{
back->data = back->next->data;
del = back->next;
back->next = back->next->next;
free(del);
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)