以前实现过链表的简单函数,详细见http://blog.csdn.net/dove1202ly/article/details/77168657
今天我们来看看链表涉及的面试题相信大家都知道单链表面试题的重要性,既然知道,我们就应该把思路捋清楚,然后多敲几遍多敲几遍多敲几遍(重要的事情说三遍),在我身边好多编程好的把这几个函数敲了不下十遍,而我太菜,这才是第一次下定决心把这个整理出来,如果有不对的地方,请多多指正,谢谢(^U^)ノ~YO
首先定义一个节点结构体:
typedef int DataType;
typedef struct ListNode
{
DataType data;
struct ListNode* next;
} ListNode;
1.链表的逆序打印(递归实现)
思路分析:
实现代码:
void Reverse(ListNode* plist)
{
if (plist == NULL)
{
return;
}
else if (plist != NULL)
{
Reverse(plist->next);
printf("%d-->", plist->data);
}
}
测试代码:
void Test1()// Reverse
{
ListNode* list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
Display(list);
Reverse(list);
Destroy(&list);
}
2、删除无头链表的非尾节点
思路分析:
实现代码:
void RemoveNotHead(ListNode** ppList, DataType x)//删除无头链表的非尾节点
{
ListNode* del = NULL;
ListNode* cur = Find(*ppList, x);
assert(ppList);
if (cur == NULL)
{
return;
}
del = cur->next;
cur->data = del->data;
cur->next = del->next;
free(del);
}
测试代码:
void Test2()//RemoveNotHead
{
ListNode* list = NULL;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
Display(list);
RemoveNotHead(&list, 3);
Display(list);
Destroy(&list);
}
3、在无头单链表的一个节点前插入一个节点
思路分析:
实现代码:
void InsertNonFront(ListNode* pos, DataType x)
{
ListNode* cur = pos->next;
ListNode* tmp = BuyNode(x);
DataType _tmp;
assert(pos);
pos->next = tmp;
tmp->next = cur;
_tmp = pos->data;//交换tmp与pos的值
pos->data = tmp->data;
tmp->data = _tmp;
}
测试代码:
void Test3()//InsertNonFront
{
ListNode* list = NULL;
ListNode* pos = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 4);
pos = Find(list, 4);
Display(list);
InsertNonFront(pos, 3);
Display(list);
Destroy(&list);
}
4、逆置单链表
思路分析:
实现代码:
ListNode* _Reverse(ListNode* pList)
{
ListNode* NewList = NULL;
ListNode* cur = pList;
while (cur)
{
//1.摘节点
ListNode* tmp = cur;
cur = cur->next;
//2.头插
tmp->next = NewList;
NewList = tmp;
}
return NewList;
}
测试代码:
void Test4()//_Reverse
{
ListNode* list = NULL;
ListNode* pos = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
pos = Find(list, 4);
Display(list);
list = _Reverse(list);
Display(list);
Destroy(&list);
}
5、约瑟夫环
思路分析:
实现代码:
ListNode* JosephRing(ListNode* list, int k)
{
ListNode* cur = list;
int count = k;
ListNode* Next = cur->next;
if (list == NULL)
{
return NULL;
}
while (cur->next != cur)
{
while (--count)
{
cur = cur->next;
}
cur->data = Next->data;
cur->next = Next->next;
free(Next);
}
return cur;
}
测试代码:
void Test5()//JosephRing
{
ListNode* list = NULL;
ListNode* pos = NULL;
ListNode* last = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
PushBack(&list, 4);
pos = Find(list, 4);
last = JosephRing(list, 3);
pos->next = list;
printf("幸存者:%d\n", last->data);
free(last);
list = last = NULL;
}
6、对链表的冒泡排序
思路分析:
实现代码:
void BubbleSortList(ListNode* plist) //冒泡排序链表
{
ListNode* cur = plist;
ListNode* tail = NULL;
if ((cur == NULL) || (cur->next == NULL))
{
return;
}
while (cur->next!= tail)//总趟数
{
while (cur->next != tail)
{
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;
}
}
测试代码:
void Test6()//BubbleSortList
{
ListNode* list=NULL;
PushBack(&list,1);
PushBack(&list,4);
PushBack(&list,2);
PushBack(&list,3);
Display(list);
BubbleSortList(list);
Display(list);
Destroy(&list);
}
7、找链表的中间节点
思路分析:
实现代码:
ListNode* FindMidNode(ListNode* pList)
{
ListNode* fast = pList;
ListNode* slow = pList;
if (pList == NULL)
{
return NULL;
}
while (fast != NULL&&fast->next != NULL)
{
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
测试代码:
void Test7()//FindMidNode
{
ListNode* list = NULL;
ListNode* ret = NULL;
PushBack(&list, 1);
PushBack(&list, 2);
PushBack(&list, 3);
Display(list);
ret = FindMidNode(list);
printf("中间节点是:%d\n", ret->data);
Destroy(&list);
}
8、有序合并两个单链表
思路分析:
实现代码:
ListNode* Merge(ListNode** ppl1, ListNode** ppl2) //合并两个有序链表
{
ListNode* head = NULL;
ListNode* cur = NULL;
assert(ppl1 != NULL);
assert(ppl2 != NULL);
if ((*ppl1)->data < (*ppl2)->data)
{
head = *ppl1;
cur = head;
*ppl1 = (*ppl1)->next;
}
else
{
head = *ppl2;
cur = head;
*ppl2 = (*ppl2)->next;
}
while ((*ppl1 != NULL) && (*ppl2 != NULL))
{
if ((*ppl1)->data < (*ppl2)->data)
{
cur->next = *ppl1;
*ppl1 = (*ppl1)->next;
}
else
{
cur->next = *ppl2;
*ppl2 = (*ppl2)->next;
}
cur = cur->next;
}
if (*ppl1 != NULL)
{
cur->next = *ppl1;
}
else if (*ppl2 != NULL)
{
cur->next = *ppl2;
}
return head;
}
ListNode* IsCycle(ListNode* pList)
{
ListNode* slow = pList;
ListNode* fast = pList;
while (fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
测试代码:
void Test8()//Merge
{
ListNode* list1 = NULL;
ListNode* list2 = NULL;
ListNode* list3 = NULL;
PushBack(&list1, 2);
PushBack(&list1, 4);
PushBack(&list1, 5);
PushBack(&list2, 1);
PushBack(&list2, 3);
list3 = Merge(&list1, &list2);
Display(list3);
Destroy(&list3);
}
9、判断链表是否带环
思路分析:
实现代码:
ListNode* IsCycle(ListNode* pList)
{
ListNode* slow = pList;
ListNode* fast = pList;
while (fast&&fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (fast == slow)
{
return fast;
}
}
return NULL;
}
测试代码:
void Test9()//IsCycle
{
ListNode* list = NULL;
ListNode* Head;
ListNode* Tail;
ListNode* ret;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PushFront(&list, 6);
Head = Find(list, 4);
Tail = Find(list, 6);
Head->next = Tail;
ret = IsCycle(list);
if (ret == NULL)
{
printf("不带环\n");
}
else
{
printf("带环\n");
}
}
10、链表若带环,求环的长度
思路分析:
实现代码:
int GetCycleLength(ListNode* Meet)
{
ListNode* meet = NULL;
int count = 0;
if (Meet == NULL)
{
return count;
}
meet = IsCycle(Meet);
Meet = meet;
meet = meet->next;
count++;
while (meet != Meet)
{
count++;
meet = meet->next;
}
return count;
}
测试代码:
void Test10()//GetCycleLength
{
ListNode* list = NULL;
ListNode* Head;
ListNode* Tail;
int ret = 0;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PushFront(&list, 6);
Head = Find(list, 4);
Tail = Find(list, 6);
Head->next = Tail;
ret = GetCycleLength(list);
printf("Length=%d\n", ret);
}
11、若带环,求环的入口点
思路分析:
定义两个指针,一个指针从链表开始出发,另一个指针从相遇点出发,两个指针再次相遇的点就是入口点
实现代码:
ListNode* GetCircleEntryNode(ListNode* meet, ListNode* plist)
{
ListNode* first = meet;
ListNode* second = plist;
if ((plist == NULL) || (meet == NULL))
{
return NULL;
}
while (first != second)
{
first = first->next;
second = second->next;
}
return first;
}
测试代码:
void Test11()//GetCircleEntryNode
{
ListNode* list = NULL;
ListNode* Head;
ListNode* Tail;
ListNode* meet;
ListNode* ret;
PushFront(&list, 1);
PushFront(&list, 2);
PushFront(&list, 3);
PushFront(&list, 4);
PushFront(&list, 5);
PushFront(&list, 6);
Head = Find(list, 4);
Tail = Find(list, 6);
Head->next = Tail;
meet = IsCycle(list);
ret = GetCircleEntryNode(meet, list);
if (ret == NULL)
{
printf("NOCYCLE\n");
}
else
{
printf("the entry is:%d\n", ret->data);
}
}
12、判断两环是否相交
思路分析:
法1:先比较两个链表,找出长链表,定义两个指针,先让一个指针从长链表走相差步,另一个指针再从短链表走,当两个链表同时指向同一个节点,带节点为相交点
实现代码:
ListNode* GetCrossNode(ListNode* l1, ListNode*l2)//判断是否相交
{
int len1 = 0;
int len2 = 0;
ListNode* cur1 = l1;
ListNode* cur2 = l2;
ListNode* shortlist, *longlist;
if (cur1 == NULL || cur1 == NULL)
return NULL;
while (cur1)
{
len1++;
cur1 = cur1->next;
}
while (cur2)
{
len2++;
cur2 = cur2->next;
}
shortlist = l2;
longlist = l1;
if (len2 > len1)
{
shortlist = l1;
longlist = l2;
}
int gap = abs(len1 - len2);
while (gap--)
{
longlist = longlist->next;
}
while (shortlist != longlist)
{
shortlist = shortlist->next;
longlist = longlist->next;
}
}
法2:如果相交,两节点尾地址相同,那么可以转化为带环问题;
将第一个链表的尾部的next指向第二个链表的头部,把问题转化为求环的入口点的问题 ;
实现代码:
ListNode* GetCrossNode(ListNode* l1, ListNode*l2)//判断是否相交
{
ListNode* cur1 = l1;
ListNode* cur2 = l2;
ListNode* meet = NULL;
while (cur1->next)
{
cur1 = cur1->next;
}
cur1->next = cur2;
meet = IsCycle(l1);
if (meet == NULL)
{
return NULL;
}
else
{
return GetCircleEntryNode(meet, l1);
}
}
}
测试代码:
void Test12()//GetCrossNode
{
ListNode* list1 = NULL;
ListNode* list2 = NULL;
PushFront(&list1, 10);
PushFront(&list1, 9);
PushFront(&list1, 7);
PushFront(&list1, 5);
PushFront(&list1, 3);
PushFront(&list1, 1);
PushFront(&list2, 6);
PushFront(&list2, 4);
PushFront(&list2, 2);
Display(list1);
Display(list2);
Find(list2,6)->next = Find(list1,7);
ListNode* ret = NULL;
ret = GetCrossNode(list1, list2);
if (ret == NULL)
printf("不相交\n");
printf("相交点 = %d\n",ret->data);
}
13、删除倒数第K个节点
思路分析:
实现代码:
void DelLinklist(ListNode* plist, int k)
{
ListNode* fast = plist;
ListNode* slow = plist;
ListNode* Del = NULL;
if (plist == NULL)
{
return;
}
while ((fast != NULL) && (fast->next != NULL))
{
while (--k > 0)
{
Del = fast;
fast = fast->next;
}
fast = fast->next;
slow = slow->next;
}
Del = slow->next;
slow->data = Del->data;
slow->next = Del->next;
free(Del);
Del = NULL;
}
测试代码:
void Test13()//DelLinklist
{
ListNode* list1 = NULL;
PushFront(&list1, 10);
PushFront(&list1, 9);
PushFront(&list1, 7);
PushFront(&list1, 5);
PushFront(&list1, 3);
PushFront(&list1, 1);
DelLinklist(list1, 3);
Display(list1);
Destroy(&list1);
}