热门题---链表面试题总结
2016-06-24 00:34
375 查看
单链表一直是面试中的重点,今天就把常见的单链表面试题总结了一下
冒泡排序:
先将tail置为空,让prev和cur不停的往前走,条件cur不等于tail 控制每一趟冒泡,找出每次的最大值,再用prev不等于tail控制每一层冒泡,每趟交换完成后将prev的值给tail,让tail 不停的往前走,
代码实现
合并两个有序链表,合并后链表依然有序,
比较两条链表的第一个节点的大小,让新链表的头指向比较后的结果,如上图中指向第二条链表的第一个节点,则让指向cur2往后走,再与cur1进行比较,newhead的next指向下一个比较后的结果
代码实现
约瑟夫环的问题
代码实现
链表相交问题:
链表不带环相交
(1)一旦两个链表相交,那么两个链表中的节点一定有相同地址。
(2)一旦两个链表相交,那么两个链表从相交节点开始到尾节点一定都是相同的节点。
只有这一种情况,一共有四种解决方法
直接将两个链表中的节点进行比较,如果节点相同就说明链表相交,如果直到其中一个链表遍历完都没有找到相同节点,说明链表不相交。但效率很低
如果两个链表相交,则链表最后一个节点肯定相同,则只需判断链表的最后一个节点是否相同,相同则说明两链表相交
将链表一的尾节点指针指向链表二的头节点,判断链表是否有环,如果链表有环则两链表相交,如果链表无环,则证明两链表不相交,优化想法:因为链表二的头节点肯定在环中,所以可以直接从链表二的头节点开始判断
将链表一建立hash表,用链表二中的节点在hash表中进行查询,看是否有相同节点,缺点:增加了内存消耗
代码实现
复杂链表的拷贝
代码实现
下面是用c++的引用实现的一份功能相同的代码
代码实现
//冒泡排序
void Bubble(SListNode* pHead)
{
int exange = 0;
if (pHead == NULL || pHead->next == NULL)
{
return;
}
SListNode* prev = pHead;
SListNode* cur = pHead->next;
SListNode* Tail = NULL;
while (Tail != pHead)
{
cur = pHead->next;
prev = pHead;
while (cur != Tail)
{
if (prev->data > cur->data)
{
DataType x;
x = cur->data;
cur->data = prev->data;
prev->data = x;
}
prev = cur;
cur = cur->next;
}
Tail = prev;
}
}
//删除一个无头单链表的非尾节点
void DelNonTailNode(SListNode* pos)
{
assert(pos);
assert(pos->next);
SListNode* del = pos->next;
pos->data = del->data;
pos->next = del->next;
free(del);
del = NULL;
}
//在无头单链表的非头节点插入一个节点
void InsertNonTailNode(SListNode* pos,DataType x)
{
assert(pos);
SListNode* cur = Buynode(pos->data);
SListNode* temp = pos->next;
cur->next = temp;
pos->next = cur;
pos->data = x;
}
//查找单链表的中间节点并只能遍历一次链表(快慢指针)
SListNode* FindMidNode(SListNode* pHead)
{
assert(pHead);
if (pHead->next == NULL)
{
return pHead;
}
else
{
SListNode* slow = pHead;
SListNode* fast = pHead;
/* while (fast)
{
if (fast->next)
{
fast = fast->next->next;
}
else
{
break;
}
slow = slow->next;
}*/
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
return NULL;
}
//查找链表的倒数第k个节点,且只能遍历链表一次
SListNode* FindNode(SListNode* pHead, int k)
{
assert(pHead);
assert(k >= 0);
SListNode* slow = pHead;
SListNode* fast = pHead;
//有问题
/*while (fast && fast->next)
{
while (k--)
{
fast = fast->next;
}
fast = fast->next;
slow = slow->next;
}*/
while (fast && --k)
{
fast = fast->next;
if (fast == NULL)
{
return NULL;
}
}
while (fast->next)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
//从尾到头打印单链表
void PrintTailToHead(SListNode* pHead)
{
if (pHead == NULL)
{
return;
}
else
{
PrintTailToHead(pHead->next);
printf("%d ", pHead->data);
}
}
//逆置单链表 很重要
SListNode* Reverse(SListNode* pHead)
{
SListNode* cur = pHead;
SListNode* newHead = NULL;
while (cur)
{
SListNode* temp = cur;
cur = cur->next;
temp->next = newHead;
newHead = temp;
}
return newHead;
}
//单链表实现约瑟夫环
//运行时先构造环,注意在代码结尾解环
SListNode* JosePhCycle(SListNode* pHead, int m)
{
SListNode* cur = pHead;
while (1)
{
if (cur == NULL)
{
return NULL;
}
else if (cur == cur->next)//只剩一个节点
{
return cur;
}
else
{
int x = m;
while (--x)
{
cur = cur->next;
}
SListNode* del = cur->next;
cur->data = del->data;
cur->next = del->next;
free(del);
del = NULL;
}
}
}
//合并两个有序链表,合并后依然有序
SListNode* Meragelist(SListNode* pHead1, SListNode* pHead2)
{
if (pHead1 == NULL)
{
return pHead2;
}
if (pHead2 == NULL)
{
return pHead1;
}
/*SListNode* newHead = pHead1->data < pHead2->data ? pHead1:pHead2;
while (pHead1 == NULL || pHead2 == NULL)
{
if (pHead1->data < pHead2->data)
{
newHead = pHead1;
pHead1 = pHead1->next;
}
else if (pHead1->data == pHead2->data)
{
newHead = pHead1;
newHead->next = pHead2;
pHead1 = pHead1->next;
pHead2 = pHead2->next;
}
else
{
newHead = pHead2;
pHead2 = pHead2->next;
}
newHead = newHead->next;
newHead->next = NULL;
}
while (pHead1)
{
newHead->next = pHead1;
pHead1 = pHead1->next;
}
while (pHead2)*/
SListNode* newHead = NULL;
SListNode* cur1 = pHead1;
SListNode* cur2 = pHead2;
if (cur1->data < cur2->data)
{
newHead = cur1;
cur1 = cur1->next;
}
SListNode* Tail = newHead;
while (cur1 && cur2)
{
if (cur1->data < cur2->data)
{
Tail->next = cur1;
cur1 = cur1->next;
}
else
{
Tail->next = cur2;
cur2 = cur2->next;
}
Tail = Tail->next;
Tail->next = NULL;
}
if (cur1 != NULL)
{
Tail->next = cur1;
}
if (cur2 != NULL)
{
Tail->next = cur2;
}
return newHead;
}
//判断链表是否带环(可以用快慢指针解决)
bool IsSListCycle(SListNode* pHead)
{
if (pHead == NULL)
{
printf("The SList is empty\n");
return false;
}
SListNode* slow = pHead;
SListNode* fast = pHead;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
SListNode* cur = slow;
int length = 0; //环的长度
do
{
slow = slow->next;
length++;
} while (cur != slow);
printf("%d\n", length);
printf("The SList have cycle\n");
return true;
}
}
printf("The SList NO cycle\n");
return false;
}
//环的入口点
SListNode* CycleEntry(SListNode* pHead)
{
if (pHead == NULL)
{
printf("The SList is empty\n");
return NULL;
}
SListNode* slow = pHead;
SListNode* fast = pHead;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return slow;
}
}
}
//链表是否相交,若相交,求交点(不带环)
SListNode* IsItersect(SListNode* pHead1,SListNode* pHead2)
{
if (pHead1 == NULL)
{
printf("链表不相交\n");
return pHead2;
}
if (pHead2 == NULL)
{
printf("链表不相交\n");
return pHead1;
}
SListNode* cur1 = pHead1;
SListNode* cur2 = pHead2;
while (cur1 && cur2)
{
if (cur1 == cur2)
{
printf("链表相交,交点为:%d\n", cur1->data);
return cur1;
}
cur1 = cur1->next;
cur2 = cur2 ->next;
}
return NULL;
}
单链表一直是面试中的重点,今天就把常见的单链表面试题总结了一下
冒泡排序:
先将tail置为空,让prev和cur不停的往前走,条件cur不等于tail 控制每一趟冒泡,找出每次的最大值,再用prev不等于tail控制每一层冒泡,每趟交换完成后将prev的值给tail,让tail 不停的往前走,
代码实现
void Bubble(pLinkList list) { pLinkNode cur = NULL; pLinkNode prev = NULL; pLinkNode tail = NULL; int exage = 0; assert(list); cur = list->pHead; if (list->pHead == NULL) { return; } while (list->pHead != tail) { prev = list->pHead; cur = prev->next; while (cur != tail) { exage = 0; if (cur->data < prev->data) { DataType x = cur->data; cur->data = prev->data; prev->data = x; exage = 1; } prev = cur; cur = cur->next; } tail = prev; if (exage == 0) { return; } } }
合并两个有序链表,合并后链表依然有序,
比较两条链表的第一个节点的大小,让新链表的头指向比较后的结果,如上图中指向第二条链表的第一个节点,则让指向cur2往后走,再与cur1进行比较,newhead的next指向下一个比较后的结果
代码实现
pLinkNode MerageSortList(pLinkList p1, pLinkList p2)//合并两个有序链表 { assert(p1); assert(p2); if (p1->pHead == NULL) return p2->pHead; if (p2->pHead == NULL) return p1->pHead; pLinkNode cur1 = p1->pHead; pLinkNode cur2 = p2->pHead; pLinkNode newHead = cur1->data < cur2->data ? p1->pHead:p2->pHead; pLinkNode Tail = newHead; while (cur1&&cur2) { if (cur1->data > cur2->data) { Tail ->next = cur1; cur1 = cur1->next; } else { Tail ->next = cur2; cur2 = cur2->next; } Tail = Tail->next; Tail->next = NULL; } if (cur1) { Tail->next = cur1; } if (cur2) { Tail->next = cur2; } return newHead; }
约瑟夫环的问题
代码实现
pLinkNode JosePhCycle(pLinkList p, size_t m)//约瑟夫环 { pLinkNode cur = p->pHead; assert(p); while (1) { if (cur == NULL) return NULL; else if (cur == cur->next)//只剩一个节点了 return cur; else { int x = m; while (--x) { cur = cur->next; } pLinkNode del = cur->next; cur->data = del->data; cur->next = del->next; free(del); del = NULL; } } }
链表相交问题:
链表不带环相交
(1)一旦两个链表相交,那么两个链表中的节点一定有相同地址。
(2)一旦两个链表相交,那么两个链表从相交节点开始到尾节点一定都是相同的节点。
只有这一种情况,一共有四种解决方法
直接将两个链表中的节点进行比较,如果节点相同就说明链表相交,如果直到其中一个链表遍历完都没有找到相同节点,说明链表不相交。但效率很低
如果两个链表相交,则链表最后一个节点肯定相同,则只需判断链表的最后一个节点是否相同,相同则说明两链表相交
将链表一的尾节点指针指向链表二的头节点,判断链表是否有环,如果链表有环则两链表相交,如果链表无环,则证明两链表不相交,优化想法:因为链表二的头节点肯定在环中,所以可以直接从链表二的头节点开始判断
将链表一建立hash表,用链表二中的节点在hash表中进行查询,看是否有相同节点,缺点:增加了内存消耗
代码实现
pLinkNode IslistCricle1(pLinkList plist1, pLinkList plist2) { assert(plist1); assert(plist2); pLinkNode cur1 = plist1->pHead; pLinkNode cur2 = plist2->pHead; if (plist1->pHead == NULL) { printf("链表不相交\n"); return NULL; } if (plist2->pHead == NULL) { printf("链表不相交\n"); return NULL; } while (cur1 && cur2) { cur1 = plist1->pHead; while (cur1&&cur2) { if (cur1 == cur2) { printf("链表相交于%d结点\n", cur1->data); return cur1; } cur1 = cur1->next; //cur2 = cur2->next; } cur2 = cur2->next; } return NULL; } void IslistCricle2(pLinkList plist1, pLinkList plist2) { assert(plist1); assert(plist2); pLinkNode cur1 = plist1->pHead; pLinkNode cur2 = plist2->pHead; if (plist1->pHead == NULL) { printf("链表不相交\n"); return; } if (plist2->pHead == NULL) { printf("链表不相交\n"); return; } while (cur1->next) { cur1 = cur1->next; } while (cur2->next) { cur2 = cur2->next; } if (cur1 == cur2) { printf("链表相交\n"); } return; } pLinkNode IslistCricle3(pLinkList plist1, pLinkList plist2) { assert(plist1); assert(plist2); pLinkNode cur1 = plist1->pHead; pLinkNode cur2 = plist2->pHead; if (plist1->pHead == NULL) { printf("链表不相交\n"); return NULL; } if (plist2->pHead == NULL) { printf("链表不相交\n"); return NULL; } while (cur2->next) { cur2 = cur2->next; } cur2->next = cur1; cur2 = plist2->pHead; cur1 = plist1->pHead; while (cur2&&cur2->next) { cur1 = cur1->next; cur2 = cur2->next->next; if (cur1 == cur2) { printf("链表相交\n"); return cur1; } } }
复杂链表的拷贝
代码实现
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <malloc.h> typedef int Datatype; typedef struct Complex { Datatype data; Complex* next; Complex* redom; }Complex, *pComplex; pComplex BuyNode(Datatype x) { pComplex tmp = (pComplex)malloc(sizeof(Complex)); if (tmp) { tmp->data = x; tmp->next = NULL; tmp->redom = NULL; } return tmp; } void Printf(pComplex head) { while (head) { printf("head:%d,redom->%d\n", head->data, head->redom->data); head = head->next; } } pComplex CopyComplexLinkList(pComplex head) { pComplex newhead = head; pComplex tail = head; pComplex cur = head; while (cur) { pComplex tmp = BuyNode(cur->data); tmp->next = cur->next; cur->next = tmp; cur = cur->next->next; } cur = head; while (cur) { cur->next->redom = cur->redom; cur = cur->next->next; } cur = head; newhead = cur->next; while (cur && cur->next) { tail = cur->next; tail = tail->next; cur->next = cur->next->next; cur = cur->next; } return newhead; } void Test() { pComplex c1 = BuyNode(1); pComplex c2 = BuyNode(2); pComplex c3 = BuyNode(3); pComplex c4 = BuyNode(4); pComplex c5 = BuyNode(5); c1->next = c2; c2->next = c3; c3->next = c4; c4->next = c5; c1->redom = c3; c2->redom = c4; c3->redom = c5; c4->redom = c1; c5->redom = c2; c1 = CopyComplexLinkList(c1); Printf(c1); } int main() { Test(); system("pause"); return 0; }
下面是用c++的引用实现的一份功能相同的代码
代码实现
//冒泡排序
void Bubble(SListNode* pHead)
{
int exange = 0;
if (pHead == NULL || pHead->next == NULL)
{
return;
}
SListNode* prev = pHead;
SListNode* cur = pHead->next;
SListNode* Tail = NULL;
while (Tail != pHead)
{
cur = pHead->next;
prev = pHead;
while (cur != Tail)
{
if (prev->data > cur->data)
{
DataType x;
x = cur->data;
cur->data = prev->data;
prev->data = x;
}
prev = cur;
cur = cur->next;
}
Tail = prev;
}
}
//删除一个无头单链表的非尾节点
void DelNonTailNode(SListNode* pos)
{
assert(pos);
assert(pos->next);
SListNode* del = pos->next;
pos->data = del->data;
pos->next = del->next;
free(del);
del = NULL;
}
//在无头单链表的非头节点插入一个节点
void InsertNonTailNode(SListNode* pos,DataType x)
{
assert(pos);
SListNode* cur = Buynode(pos->data);
SListNode* temp = pos->next;
cur->next = temp;
pos->next = cur;
pos->data = x;
}
//查找单链表的中间节点并只能遍历一次链表(快慢指针)
SListNode* FindMidNode(SListNode* pHead)
{
assert(pHead);
if (pHead->next == NULL)
{
return pHead;
}
else
{
SListNode* slow = pHead;
SListNode* fast = pHead;
/* while (fast)
{
if (fast->next)
{
fast = fast->next->next;
}
else
{
break;
}
slow = slow->next;
}*/
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
return NULL;
}
//查找链表的倒数第k个节点,且只能遍历链表一次
SListNode* FindNode(SListNode* pHead, int k)
{
assert(pHead);
assert(k >= 0);
SListNode* slow = pHead;
SListNode* fast = pHead;
//有问题
/*while (fast && fast->next)
{
while (k--)
{
fast = fast->next;
}
fast = fast->next;
slow = slow->next;
}*/
while (fast && --k)
{
fast = fast->next;
if (fast == NULL)
{
return NULL;
}
}
while (fast->next)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
//从尾到头打印单链表
void PrintTailToHead(SListNode* pHead)
{
if (pHead == NULL)
{
return;
}
else
{
PrintTailToHead(pHead->next);
printf("%d ", pHead->data);
}
}
//逆置单链表 很重要
SListNode* Reverse(SListNode* pHead)
{
SListNode* cur = pHead;
SListNode* newHead = NULL;
while (cur)
{
SListNode* temp = cur;
cur = cur->next;
temp->next = newHead;
newHead = temp;
}
return newHead;
}
//单链表实现约瑟夫环
//运行时先构造环,注意在代码结尾解环
SListNode* JosePhCycle(SListNode* pHead, int m)
{
SListNode* cur = pHead;
while (1)
{
if (cur == NULL)
{
return NULL;
}
else if (cur == cur->next)//只剩一个节点
{
return cur;
}
else
{
int x = m;
while (--x)
{
cur = cur->next;
}
SListNode* del = cur->next;
cur->data = del->data;
cur->next = del->next;
free(del);
del = NULL;
}
}
}
//合并两个有序链表,合并后依然有序
SListNode* Meragelist(SListNode* pHead1, SListNode* pHead2)
{
if (pHead1 == NULL)
{
return pHead2;
}
if (pHead2 == NULL)
{
return pHead1;
}
/*SListNode* newHead = pHead1->data < pHead2->data ? pHead1:pHead2;
while (pHead1 == NULL || pHead2 == NULL)
{
if (pHead1->data < pHead2->data)
{
newHead = pHead1;
pHead1 = pHead1->next;
}
else if (pHead1->data == pHead2->data)
{
newHead = pHead1;
newHead->next = pHead2;
pHead1 = pHead1->next;
pHead2 = pHead2->next;
}
else
{
newHead = pHead2;
pHead2 = pHead2->next;
}
newHead = newHead->next;
newHead->next = NULL;
}
while (pHead1)
{
newHead->next = pHead1;
pHead1 = pHead1->next;
}
while (pHead2)*/
SListNode* newHead = NULL;
SListNode* cur1 = pHead1;
SListNode* cur2 = pHead2;
if (cur1->data < cur2->data)
{
newHead = cur1;
cur1 = cur1->next;
}
SListNode* Tail = newHead;
while (cur1 && cur2)
{
if (cur1->data < cur2->data)
{
Tail->next = cur1;
cur1 = cur1->next;
}
else
{
Tail->next = cur2;
cur2 = cur2->next;
}
Tail = Tail->next;
Tail->next = NULL;
}
if (cur1 != NULL)
{
Tail->next = cur1;
}
if (cur2 != NULL)
{
Tail->next = cur2;
}
return newHead;
}
//判断链表是否带环(可以用快慢指针解决)
bool IsSListCycle(SListNode* pHead)
{
if (pHead == NULL)
{
printf("The SList is empty\n");
return false;
}
SListNode* slow = pHead;
SListNode* fast = pHead;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
SListNode* cur = slow;
int length = 0; //环的长度
do
{
slow = slow->next;
length++;
} while (cur != slow);
printf("%d\n", length);
printf("The SList have cycle\n");
return true;
}
}
printf("The SList NO cycle\n");
return false;
}
//环的入口点
SListNode* CycleEntry(SListNode* pHead)
{
if (pHead == NULL)
{
printf("The SList is empty\n");
return NULL;
}
SListNode* slow = pHead;
SListNode* fast = pHead;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return slow;
}
}
}
//链表是否相交,若相交,求交点(不带环)
SListNode* IsItersect(SListNode* pHead1,SListNode* pHead2)
{
if (pHead1 == NULL)
{
printf("链表不相交\n");
return pHead2;
}
if (pHead2 == NULL)
{
printf("链表不相交\n");
return pHead1;
}
SListNode* cur1 = pHead1;
SListNode* cur2 = pHead2;
while (cur1 && cur2)
{
if (cur1 == cur2)
{
printf("链表相交,交点为:%d\n", cur1->data);
return cur1;
}
cur1 = cur1->next;
cur2 = cur2 ->next;
}
return NULL;
}
相关文章推荐
- 一个简短的对话辐射出来的it面试经验
- 女程序员在互联网界到底有没有被歧视?
- 顶尖程序员不同于常人的5个区别
- 面试当中一些注意的点
- 面试之我见
- 职场培训师的一些建议
- 面试题 一
- 让年轻程序员少走弯路的 14 个忠告
- PHP面试题:50,40,30,20,1这五张优惠卷,订单金额为X元,用方法实现return多少张优惠卷
- 面试2
- js 面试大全
- 在你步入职业软件开发生涯那天起就该知道的五件事
- 记自己写的第一个批处理
- 程序员修炼之道——从小工到专家阅读笔记03
- 操作系统面试—进程同步
- 程序员修炼之道——从小工到专家阅读笔记02
- 文章标题
- 易车面试题
- 关于java socket多用户聊天--图形界面版&带高层架构思想(经典面试题)
- arm9 mini2440 10道面试题