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

【面试题】单链表的操作2

2016-01-19 10:57 459 查看
单链表的建立、插入等替他操作见本人博客:单链表的基本操作 http://10741357.blog.51cto.com/10731357/1736387【面试题】单链表的操作1 http://10741357.blog.51cto.com/10731357/1736395介绍了4种有关单链表的面试题,对于以下链表要求的实现,解题的思路很重要。例如两个有序链表的合并,实现约瑟夫环及链表成环问题。各函数的实现,代码如下:
SListNode* MergeList(SListNode* L1, SListNode* L2)//合并两个有序链表,合并后依然有序
{//认为不带头结点的单链表,注意应判断两个链表是否为空
if (L1 == NULL)
return L2;
if (L2 == NULL)
return L1;
//if (L1 || L2)
//	return L1 = NULL ? L2 : L1;
SListNode* NewHead = NULL;
SListNode* pHead1 = L1;
SListNode* pHead2 = L2;
//进行一次比较,找出较小的值,使NewHead指向新链表的头结点
if (pHead1->data < pHead2->data)
{
NewHead = pHead1;
pHead1 = pHead1->next;
}
else
{
NewHead = pHead2;
pHead2 = pHead2->next;
}
//用tail指针进行比较和移动
SListNode* tail = NewHead;
while (pHead1 && pHead2)
{
if (pHead1->data < pHead2->data)
{
tail->next = pHead1;
pHead1 = pHead1->next;
}
else
{
tail->next = pHead2;
pHead2 = pHead2->next;
}
tail = tail->next;
}
//如果两个链表不一样长时,将其链接在新链表的后面
if (pHead1)
tail->next = pHead1;
else
tail->next = pHead2;
return NewHead;
}

void BubbleSort(SListNode* pHead)//冒泡排序单链表
{
if (pHead == NULL || pHead->next == NULL)
return;
int exchange = 0;//标志位判断排序是否已达到有序
SListNode* tail = pHead->next;//比较n-1趟
while (tail)
{//两个指针cur,next进行比较和移动
SListNode* cur = pHead;
SListNode* next = pHead->next;
while (next)
{
if (cur->data > next->data)
{
exchange = 1;
DataType tmp = cur->data;
cur->data = next->data;
next->data = tmp;
}
cur = cur->next;
next = next->next;
}
if (exchange == 0)//如果没有发生交换,则链表已有序
break;
tail = tail->next;
}
}

SListNode* JosephCycle(SListNode* pHead, int k)//单链表实现约瑟夫环
{//判断链表及k是否有效
if (pHead == NULL || k <= 0)
return NULL;
SListNode* cur = pHead;
while (1)
{
if (cur->next == cur)
return cur;
int count = k;
while (--count)
cur = cur->next;
//替换法删除结点
SListNode* next = cur->next;
cur->data = next->data;
cur->next = next->next;
free(next);
}
return NULL;
}

//判断单链表是否带环?若带环,求环长度,求环入口点
SListNode* CheckCycle(SListNode* pHead)//检查是否带环
{//利用快慢指针,慢指针走一步,快指针走两步;如果存在环,两个指针一定会相遇。
if (pHead == NULL || pHead->next == NULL)
return NULL;
SListNode* slow = pHead;
SListNode* fast = pHead;
while (fast && fast->next)//条件为fast和fast->next都不为空
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
return slow;//如何带环返回相遇的结点
}
return NULL;
}

int GetCycleLength(SListNode* MeetNode)//求环的长度
{//检查是否带环,即存在相遇点,走一圈就可以求出环的长度
assert(MeetNode);
SListNode* cur = MeetNode;
int count = 0;
do
{
count++;
cur = cur->next;
} while (cur != MeetNode);
return count;
}

SListNode* GetEntryNode1(SListNode* pHead)//求环的入口地址
{//检查是否有环,通过快慢指针分别从头结点和相遇结点处开始走,相遇点即为入口结点
if (pHead == NULL || pHead->next == NULL)
return NULL;
SListNode* meetnode = CheckCycle(pHead);
SListNode* slow = pHead;
SListNode* fast = meetnode;
while(slow && fast)
{
if (slow == fast)
return fast;
slow = slow->next;
fast = fast->next;
}
return NULL;
}

int SListLength(SListNode* pHead)//分别求环形链表被拆成两条链表的链表长度
{
if (pHead == NULL)
return 0;
int count = 0;
SListNode* cur = pHead;
while (cur)
{
cur = cur->next;
count++;
}
return count;
}

SListNode* GetEntryNode2(SListNode* pHead)//求环的入口地址---两个链表相交思想
{//检查是否有环,在聚点处截断,求出两个链表相交点即为入口地址
if (pHead == NULL || pHead->next == NULL)
return NULL;
SListNode* cur1 = pHead;
SListNode* cur2 = CheckCycle(pHead)->next;
CheckCycle(pHead)->next = NULL;//此法造成数据丢失
int len1 = SListLength(cur1);
int len2 = SListLength(cur2);
PrintSList(cur1);
printf("\n---------------------\n");
PrintSList(cur2);
int errand;//两个链表的长度差
//长链表先走errand步
if (len1 > len2)
{
errand = len1 - len2;
while (errand--)
cur1 = cur1->next;
}
else
{
errand = len2 - len1;
while (errand--)
cur2 = cur2->next;
}
//两个链表同步前进
while (cur1 != cur2)
{
cur1 = cur1->next;
cur2 = cur2->next;
}
return cur2;
}
各函数测试用例如下:
void Test10()
{//【面试题七】合并两个有序链表,合并后依然有序
SListNode* phead1 = NULL;
SListNode* phead2 = NULL;
PushBack_Cpp(phead1, 1);
PushBack_Cpp(phead1, 3);
PushBack_Cpp(phead1, 6);
PushBack_Cpp(phead2, 2);
PushBack_Cpp(phead2, 4);
PushBack_Cpp(phead2, 5);
PushBack_Cpp(phead2, 7);
SListNode* phead = MergeList(phead1,phead2);
PrintSList(phead);
printf("\n---------------------\n");
}

void Test11()
{//【面试题八】冒泡排序单链表
SListNode *phead = NULL;
PushBack_Cpp(phead, 4);
PushBack_Cpp(phead, 5);
PushBack_Cpp(phead, 3);
PushBack_Cpp(phead, 2);
PushBack_Cpp(phead, 6);
PushBack_Cpp(phead, 1);
PrintSList(phead);
printf("\n---------------------\n");
BubbleSort(phead);
PrintSList(phead);
}

void Test12()
{//【面试题九】单链表实现约瑟夫环
SListNode *phead = NULL;
PushBack_Cpp(phead, 1);
PushBack_Cpp(phead, 2);
PushBack_Cpp(phead, 3);
PushBack_Cpp(phead, 4);
PushBack_Cpp(phead, 5);
PushBack_Cpp(phead, 6);
PrintSList(phead);
printf("\n---------------------\n");
Find(phead, 6)->next = Find(phead, 1);//将链表构成一个环,尾接头
SListNode* FindNode = JosephCycle(phead,3);
printf("%d\n",FindNode->data);
}

void Test13()
{//【面试题十】判断单链表是否带环?若带环,求环长度,求环入口点
SListNode *phead = NULL;
PushBack_Cpp(phead, 1);
PushBack_Cpp(phead, 2);
PushBack_Cpp(phead, 3);
PushBack_Cpp(phead, 4);
PushBack_Cpp(phead, 5);
PushBack_Cpp(phead, 6);
PushBack_Cpp(phead, 7);
PrintSList(phead);
printf("\n---------------------\n");
Find(phead, 6)->next = Find(phead, 3);
SListNode* meetnode = CheckCycle(phead);//检查是否带环
printf("%d\n", meetnode->data);
if (meetnode==NULL)
printf("该单链表不带环!\n");
else
{
printf("该单链表带环!\n");
int len = GetCycleLength(meetnode);//求环的长度
printf("length = %d\n", len);
SListNode* entry1 = GetEntryNode1(phead);//求环的入口地址
printf("入口处为:%d\n", entry1->data);
printf("\n---------------------\n");
SListNode* entry2 = GetEntryNode2(phead);//求环的入口地址
printf("\n入口处为:%d\n", entry2->data);
}
}
int main()
{
Test7();
printf("\n***********************\n");
Test8();
printf("\n***********************\n");
Test9();
printf("\n***********************\n");
Test10();
printf("\n***********************\n");
Test11();
printf("\n***********************\n");
Test12();
printf("\n***********************\n");
Test13();
system("pause");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息