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

单链表的面试题总结--------图形解析

2017-01-02 00:57 239 查看
1.// 删除无头单链表的非尾结点,要求:不能遍历单链表

因为没有头结点,所以不能用固有的思维去考虑这个问题,因为是单链表,所以不能由链表中的后一个节点去找前一个节点,

所以这时需要转化一种思维,不能删除一个节点的前一个节点,但是可以去删除一个节点的后一个节点,

首先应该判断pos是否为空,如果为空,直接返回,如果不为空,分析如图示(利用转换思想)

在这里还应该思考:为什么是删除非尾节点?—-如果是删除最后一个节点,那么这里的pDel就为空了,

那么如果使用下面的方法,运行pDel->next时程序就会崩溃。所以就没办法删除这个节点了。

图形解析:



代码实现:

void DeleteNotTailNode(PNode pos)
{
if (NULL == pos)
{
return ;
}
PNode pDel = pos->next;
pos->data = pDel->data;
pos->next = pDel->next;
free(pDel);
}


2.// 在无头单链表非头结点前插入新节点

使用上一题的思想,可以转换,可以在这个节点的后面插入这个节点,然后将需要插入节点的值赋给这个节点即可:

分析如图示:



代码实现:

void InsertNotHeadNode(PNode pos, DataType _data)
{
if (NULL == pos)
{
return ;
}
PNode newNode = BuyNode(pos->data);
if (newNode)
{
newNode->next = pos->next;
pos->next = newNode;
pos->data = _data;
}
}


3.// 用单链表实现约瑟夫环

首先需要构建一个环,这个很容易,只要将单链表的尾节点的next指向phead即可。

约瑟夫环是一个自杀环,是约瑟夫和他的朋友为了活下来而想出的一种办法:

包括他和他的朋友在内的41个犹太人,为了不成为敌方的俘虏而相约自杀,自杀的顺序是这样产生的,他们41个人围成一个圈,从其中任意位置开始报数,每次报到3的人自杀,然后从下一个人又开始从1报数。直到最后就会剩下1个人,约瑟夫和他的朋友就站在了最后剩下的两个位置,从而生存下来。

我们可以使用单链表来实现,先将单链表构建成一个环,每次删除掉第M个元素,直到链表只剩下一个节点,那么就返回这个节点。

需要考虑:链表为空—-直接返回

链表不空时:

①报数

②删节点

还需要特别注意是头结点,因为在删除的过程中,你可能删除掉头结点,所以最好接收最后剩下的一个节点,因为此时phead保存的节点

已经可能被释放掉了,所以不能再使用phead,而是使用pCur,因为pCur始终指向的是链表中可以访问到的当前节点。

图形解析:



代码实现:

PNode JosephCircle(PNode pHead, size_t M)
{
if (NULL == pHead)
{
return NULL;
}
PNode pCur = pHead;
PNode prev = pCur;
while (pCur != pCur->next)
{
size_t k = M;
while (--k)
{
pCur = pCur->next;
}
PNode pDel = pCur->next;
pCur->data = pDel->data;
pCur->next = pDel->next;
free(pDel);
}
return pCur;
}


4.// 逆置单链表

第一种方法–三个指针

首先考虑的还是链表为空和只有一个节点的情况—-直接返回。

还有链表中只有两个节点时,这种情况刚好在循环外可以处理。

在逆置的过程中肯定要进行循环,找到最后一个节点。



代码实现:

逆置单链表--三个指针
PNode ReverseList(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return pHead;
}
PNode prev = pHead;
PNode pCur = prev->next;
PNode pnext = pCur->next;
while (pnext)
{
pCur->next = prev;
prev = pCur;
pCur = pnext;
pnext = pnext->next;
}
pCur->next = prev;
pHead->next = NULL;
return pCur;
}


// 逆置单链表

第二种方法–头插法:

简单说明:

就是每次将原链表的头节点摘下来(pHead->next = newnode),然后头插在新链表中(此时需要更新新链表的头结点),然后原来的头结点继续向后走,因为之前已经将头结点后的节点保存下来了;循环执行,直到原链表只剩下一个节点时,直接将最后这个节点头插在新链表即可。

代码实现:

PNode ReverseList(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return pHead;
}
PNode pCur = pHead->next;
PNode newNode = NULL;
while (pCur)
{
pHead->next = newNode;
newNode = pHead;
pHead = pCur;
pCur = pCur->next;
}
pHead->next = newNode;
newNode = pHead;
return newNode;
}


5.// 查找单链表的中间结点,要求只能够遍历一次链表

首先考虑:链表为空——返回NULL;

分为两种情况:

①链表中有奇数个节点时,分析如图示:



②链表中有偶数个节点时:



代码实现:

PNode FindMidNode(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return pHead;
}
PNode pSlow = pHead;
PNode pFast = pHead;
while (pFast && pFast->next)
{
pSlow = pSlow->next;
pFast = pFast->next->next;
}
return pSlow;
}


6.// 查找单链表的倒数第K个结点,只能够遍历一次链表



代码实现:

PNode FindLastKNode(PNode pHead, size_t K)
{
if (NULL == pHead || K == 0)
{
return NULL;
}
PNode pSlow = pHead;
PNode pFast = pHead;
while (--K)
{
if (NULL == pFast)
{
return NULL;
}
pFast = pFast->next;
}
while (pFast->next)
{
pSlow = pSlow->next;
pFast = pFast->next;
}
return pSlow;
}


7.// 删除单链表的倒数第K个结点

PNode DeleteLastKNode(PNode pHead, size_t K);

由上一题可以很容易的得到第k个节点,然后调用删除的函数即可。

代码实现:

PNode DeleteLastKNode(PNode pHead, size_t K)
{
if (NULL == pHead || K == 0)
{
return NULL;
}
PNode pos = FindLastKNode(pHead,K);
Erase(&pHead,pos);
}


8.// 合并两个已序单链表,合并之后依然有序

PNode MergeList(PNode pHead1, PNode pHead2);

考虑以下因素:

pHead1为空—–返回pHead2

pHead2为空—–返回pHead1

当pHead1和pHead2都不为空时,分析如图示:



代码实现:

PNode MergeList(PNode pHead1, PNode pHead2)
{
if (NULL == pHead1)
{
return pHead2;
}
if (NULL == pHead2)
{
return pHead1;
}
PNode newNode = NULL;
PNode pTail = NULL;
if (pHead1->data < pHead2->data)
{
pTail = pHead1;
pHead1 = pHead1->next;
}
else
{
pTail = pHead2;
pHead2 = pHead2->next;
}
newNode = pTail;
while (pHead1 && pHead2)
{
if (pHead1->data < pHead2->data)
{
pTail->next = pHead1;
pTail = pHead1;
pHead1 = pHead1->next;
}
else
{
pTail->next = pHead2;
pTail = pHead2;
pHead2 = pHead2->next;
}
}
if (pHead1)
{
pTail->next = pHead1;
}
else
{
pTail->next = pHead2;
}
return newNode;
}


9.// 对单链表进行冒泡排序–升序

相信大家对冒泡排序的思想已经很熟悉了吧,如果真的有需要,可以去看一下我的冒泡排序的图形解析~当然了,如果有兴趣的话。

这里我就直接贴代码啦

void BubbleSort(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return ;
}
PNode pCur = pHead;
PNode pTail = NULL;
int flag = 0;
while (pTail != pHead)
{
pCur = pHead;
while (pCur->next != pTail)
{
if (pCur->data > pCur->next->data)
{
DataType tmp = pCur->data;
pCur->data = pCur->next->data;
pCur->next->data = tmp;
flag = 1;
}
pCur = pCur->next;
if (!flag)
{
return ;
}
}
pTail = pCur;
}
}


上面的代码都是我验证过的,我的编译器是vs2010,当然啦,因为能力有限,上面的算法或许不是最优的,可能你还有更好的方法,欢迎评论探讨,共同学习,一起进步。

最近一直在考试,忙着复习,所以只能在这个时间点来总结学习的内容,赶紧得休息啦,明天继续复习。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单链表 面试题