关于单链表的基本操作,之前已经总结过了,那些掌握之后算是了解了单链表是什么?不过现在面试的题中,肯定不会只让你回答单链表的基础操作,总是会改变一些东西,或是扩展一下。
下面就是一些关于单链表的扩展内容:
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#pragma warning (disable:4996)
#define DataType int
typedef struct PNode{
DataType data;
struct PNode* next;
}Node,*PNode;
//创建新的节点
PNode BuyNode(DataType data);
//初始化单链表
void InitList(PNode* pHead);
//尾插
void PushList(PNode* pHead, DataType data);
//打印单链表
void PrintList(PNode pHead);
// 从尾到头打印单链表
void PrintListFromTail2Head(PNode pHead);
// 删除无头单链表的非尾结点
void DeleteNotTailNode(PNode pos);
// 在无头单链表非头结点前插入置为data的结点
void InsertNotHeadNode(PNode pos, DataType data);
// 用单链表实现约瑟夫环
PNode JosephCircle(PNode pHead, size_t M);
// 逆置单链表--三个指针
PNode ReverseList(PNode pHead);
// 逆置单链表--头插法
PNode ReverseList_P(PNode pHead);
// 对单链表进行冒泡排序--升序
void BubbleSort(PNode pHead);
// 查找单链表的中间结点,要求只能够遍历一次链表
PNode FindMidNode(PNode pHead);
// 查找单链表的倒数第K个结点,只能够遍历一次链表
PNode FindLastKNode(PNode pHead, size_t K);
//// 删除单链表的倒数第K个结点
//PNode DeleteLastKNode(PNode pHead, size_t K);
//
//// 合并两个已序单链表,合并之后依然有序
//PNode MergeList(PNode pHead1, PNode pHead2);
有些内容就不能按照常规的思路来看,我记得第一次上课的时候,老师出了一道智力题,
说是有两只分布不均匀的香,但是它们都能燃烧一个小时,如果我们想要测量一刻钟的时间,该如何做?
当时很多人都说将香掐成两段,然而,香并不是均匀的,所以不行。
最后给出了答案:将两只香同时点燃,不过,要一只点燃一头,另一只点燃两头,这样,等其中一只燃烧完了之后,时间刚好过了半个小时,再将另一头也点上,这样,剩余的香就能燃烧一刻钟的时间了。
同样的道理,这里的一些问题也是这样的想法,比如求中点的问题,只要给出两个指针,慢的一次走一步,快的一次走两步,等快的走到最后,那么慢的刚好走到中间。
下面就是这些函数的实现了:
#include"LinkList.h"
//创建新的节点
PNode BuyNode(DataType data)
{
PNode Node = (PNode)malloc(sizeof(Node));
if (Node)
{
Node->data = data;
Node->next = NULL;
}
return Node;
}
//初始化单链表
void InitList(PNode * pHead)
{
assert(pHead);
(*pHead) = NULL;
}
//尾插
void PushList(PNode* pHead, DataType data)
{
assert(pHead);
PNode NewNode = BuyNode(data);
if (NULL==(*pHead))
{
(*pHead) = NewNode;
}
else
{
PNode pCur = (*pHead);
while (pCur->next)
{
pCur = pCur->next;
}
pCur->next = NewNode;
}
}
void PrintList(PNode pHead)
{
PNode pCur = pHead;
while (pCur)
{
printf("%d ", pCur->data);
pCur = pCur->next;
}
printf("\n");
}
// 从尾到头打印单链表
void PrintListFromTail2Head(PNode pHead)
{
if (pHead)
{
PrintListFromTail2Head(pHead->next);//运用递归的思想,找出最后一个节点,打印
printf("%d ", pHead->data);
}
printf("\n");
}
// 删除无头单链表的非尾结点,不能遍历单链表
void DeleteNotTailNode(PNode pos)
{
if (NULL == pos)//如果pos的位置为空,直接返回
{
return;
}
PNode pDel = pos->next;//将pos后面的节点保存
pos->data = pDel->data;//将pos后面的值,赋给pos中的data
pos->next = pDel->next;//将pos的下一个位置指向待删除的下一个位置
free(pDel);//释放空间
}
// 在无头单链表非头结点前插入置为data的结点
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;
}
}
// 用单链表实现约瑟夫环
PNode JosephCircle(PNode pHead, size_t M)
{
if (NULL == pHead)
{
return;
}
PNode pCur = pHead;
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;
}
// 逆置单链表--三个指针
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;
}
// 逆置单链表--头插法
PNode ReverseList_P(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return NULL;
}
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;
}
// 对单链表进行冒泡排序--升序
void BubbleSort(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return;
}
PNode pCur = pHead;
PNode pTail = NULL;
DataType flag = 0;
while (pTail != pHead)
{
pCur = pHead;
while (pCur->next != pTail)
{
//结构体中的next定义成PNode*的形式,才能使next继续间接访问,
if ((pCur->data) > (pCur->next->data))
{
DataType temp = pCur->data; //交换
pCur->data = pCur->next->data;
pCur->next->data = temp;
flag = 1;
}
pCur = pCur->next;
}
if (!flag)
{
return;
}
pTail = pCur;
}
}
// 查找单链表的中间结点,要求只能够遍历一次链表
PNode FindMidNode(PNode pHead)
{
if (NULL == pHead || NULL == pHead->next)
{
return;
}
//使用一快一慢两个指针,快的是慢的的二倍
PNode pslow = pHead;
PNode pfast = pHead;
while (pfast&&pfast->next)//分两种情况考虑
{
pslow = pslow->next;
pfast = pfast->next->next;
}
return pslow;//快的指针到尾部,慢的指针就在中间,所以返回慢的指针即可
}
// 查找单链表的倒数第K个结点,只能够遍历一次链表
PNode FindLastKNode(PNode pHead, size_t K)
{
if (NULL == pHead || K == 0)
{
return NULL;
}
PNode pslow = pHead;
PNode pfast = pHead;
while (--K)//先让快的指针走K步
{
if (NULL == pfast)//如果K的值大于节点数,返回空
{
return NULL;
}
pfast = pfast->next;
}
while (pfast->next)//再一起走,等到快的走到尾部,慢的刚好到倒数第K个节点
{
pfast = pfast->next;
pslow = pslow->next;
}
return pslow;//返回慢的指针即可
}
//删除单链表的倒数第K个结点
PNode DeleteLastKNode(PNode pHead, size_t K)
{
if (NULL == pHead || NULL == pHead->next)
{
return NULL;
}
PNode pos = FindLastKNode(pHead, K);
Earse(pHead, pos);
}
//合并两个已序单链表,合并之后依然有序
PNode MergeList(PNode pHead1, PNode pHead2)
{
if (NULL == pHead1)
{
return pHead2;
}
if (NULL == pHead2)
{
return pHead1;
}
PNode pTail= NULL;
PNode NewNode = 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;
}
#include"LinkList.h"
void FunTest()
{
PNode pHead;
InitList(&pHead);
PushList(&pHead,5);
PushList(&pHead, 8);
PushList(&pHead, 2);
PushList(&pHead, 7);
PushList(&pHead, 9);
PrintList(pHead);
PrintListFromTail2Head(pHead);
//
//JosephCircle(pHead, 3);
//PrintListFromTail2Head(pHead);
PNode p=FindMidNode(pHead);
printf("%d\n", p->data);
PNode p1 = FindLastKNode(pHead, 1);
printf("%d\n", p1->data);
BubbleSort(pHead);
PrintList(pHead);
}
int main()
{
FunTest();
system("pause");
return 0;
}
程序写的很欠缺,有的地方还需再进行,如果,你们有什么意见或建议,请评论……