您的位置:首页 > 职场人生

链表面试题总结(一)

2016-06-11 12:06 381 查看
基于上一次写的链表,现在,我们来讨论下面这些问题。

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);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: