//
//链表的面试题
//1.从尾到头打印单链表
//非递归
void SListPrintTailToHead(SListNode* pHead)
{
SListNode* tail = NULL;
SListNode* cur = NULL;
while (tail != NULL)
{
cur = pHead;
while (cur->_next != tail)
{
cur = cur->_next;
}
printf("%d", cur->_data);
tail = cur;
}
}
//递归
void SListPrintTailToHeadR(SListNode* pHead)
{
if (NULL != pHead->_next) //递归结束条件
SListPrintTailToHeadR(pHead->_next); //子问题
printf("%d ", pHead->_data);
}
//2.删除一个无头单链表的非尾节点(不能遍历链表)
// 用代替法,把当前节点的下一个节点的值赋值给当前节点,再delete掉当前节点的下一个节点
void SListDelNonTailNode(SListNode* pos)
{
assert(pos!=NULL && pos->_next!=NULL);
SListNode* next = pos->_next;
pos->_data = next->_data;
pos->_next = next->_next;
next->_next = NULL;
free(next);
}
//3.在无头单链表的一个节点前插入一个节点(不能遍历链表)
//把插入节点的数据放到新节点上,把新节点的数据放到插入节点的数据上
void SListInsertFrontNode(SListNode* pos, DataType x)
{
assert(pos!=NULL);
SListNode* tail = pos->_next;
SListNode* newNode = BuySListNode(pos->_data);
newNode->_data = pos->_data;
pos->_data = x;
newNode->_next = pos->_next;
pos->_next = newNode;
}
//4.单链表实现约瑟夫环
//先把链表连接成环,从1数到k,其实是往前移动k - 1次,然后删除第k个链表。当链表只剩下最后一个节点时,循环结束
SListNode* SListFrontNode(SListNode* pHead, int k)
{
SListNode* cur = pHead;
SListNode* next;
while (cur->_next != cur)
{
DataType count = k;
while (--count)//k-1次循环
{
cur = cur->_next;
}
next = cur->_next;
cur->_data = next->_data;
cur->_next = next->_next;
free(next);
}
return cur;
}
//5.逆置/反转单链表
SListNode* SListReverse1(SListNode* list)//逆置/反转单链表
{
SListNode* n1, *n2, *n3;
if (list == NULL || list->_next == NULL)
{
return list;
}
n1 = list;
n2 = n1->_next;
n3 = n2->_next;
n1->_next = NULL;
while (n2 != NULL)
{
n2->_next = n1;
n1 = n2;
n2 = n3;
if (n3 != NULL)
{
n3 = n3->_next;
}
}
return n1;
}
SListNode* SListReverse2(SListNode* list)//逆置/反转单链表
{
SListNode* cur = list;
SListNode* newNode = NULL;
while (cur != NULL)
{
SListNode* next = cur->_next;
cur->_next = newNode;
newNode = cur;
cur = next;
}
return newNode;
}
//6.单链表排序(冒泡排序&快速排序)
//冒泡排序
void SListBubbleSort(SListNode* list) //冒泡排序
{
SListNode* tail = NULL;
while (tail != list)
{
int flag = 0;
SListNode* cur = list;
SListNode* next = list->_next;
while (next != tail)
{
if (cur->_data > cur->_next->_data)
{
flag = 1;
DataType tem = cur->_data;
cur->_data = cur->_next->_data;
cur->_next->_data = tem;
}
cur = cur->_next;
next = next->_next;
}
if (0 == flag)
{
return;
}
tail = cur;
}
}
//7.合并两个有序链表, 合并后依然有序
//递归
SListNode* MergeSlist(SListNode* pHead1, SListNode* pHead2)
{
if (NULL == pHead1)
{
return pHead2;
}
else if (NULL==pHead2)
{
return pHead1;
}
SListNode* newMergeListHead = NULL;
if (pHead1->_data<pHead2->_data)
{
newMergeListHead = pHead1;
newMergeListHead->_next = MergeSList(pHead1->_next, pHead2);
}
else
{
newMergeListHead = pHead2;
newMergeListHead->_next = MergeSList(pHead1, pHead2->_next);
}
return newMergeListHead;
}
//非递归
SListNode* MergeSList(SListNode* pHead1, SListNode* pHead2)
{
if (NULL==pHead1)
{
return pHead2;
}
else if (NULL==pHead2)
{
return pHead1;
}
SListNode* newMergeListHead = NULL;//把排序好的链表存到这里面
SListNode* tail = NULL; //记录新链表最后一个节点
if (pHead1->_data<pHead2->_data)
{
newMergeListHead = pHead1;
pHead1 = pHead1->_next;
}
else
{
newMergeListHead = pHead2;
pHead2 = pHead2->_next;
}
tail = newMergeListHead;
while (pHead1!=NULL && pHead2!=NULL)
{
if (pHead1->_data<pHead2->_data)
{
tail->_next=pHead1;
pHead1 = pHead1->_next;
}
else
{
tail->_next = pHead2;
pHead2 = pHead2->_next;
}
tail = tail->_next;
}
if (NULL==pHead1)
{
tail->_next = pHead2;
}
else if (NULL==pHead2)
{
tail->_next = pHead1;
}
return newMergeListHead;
}
//8.查找单链表的中间节点,要求只能遍历一次链表
//给一个快指针,让快指针每次移动两步,给一个慢指针,让慢指针每次移动一步,
//最后结果就是快指针移动到最后一个节点,慢指针最后移动到了中间的节点上。
SListNode* FindMidNode(SListNode* list)
{
assert(list!=NULL);
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast!=NULL && pFast->_next!=NULL)
{
pFast = pFast->_next->_next;
pSlow = pSlow->_next;
}
return pSlow;
}
//9.查找单链表的倒数第k个节点,要求只能遍历一次链表
SListNode* FindReciprocalNode(SListNode* list, size_t k)
{
assert(list!=NULL && k!=0);
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast->_next!=NULL)
{
k--;
if (k <= 0)
{
pSlow = pSlow->_next;
}
pFast = pFast->_next;
}
if (k<=1)
{
return pSlow;
}
else
{
return NULL;
}
}
//10.删除链表的倒数第K个结点
void RemoveReciprocalNode(SListNode* list, int k)
{
assert(list!=NULL && k!=0);
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast->_next != NULL)
{
k--;
pFast = pFast->_next;
if (k<=0) //当pFast走到正数第K个节点时,pSlow开始走
{
pSlow = pSlow->_next;
}
}
if (k<=1)
{
SListDelNonTailNode(pSlow);
}
}
//11.判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算
SListNode* SListIsCycle(SListNode* list)
{
if (NULL==list)
{
return NULL;
}
SListNode* pFast = list;
SListNode* pSlow = list;
//如果有环,通过这两个变量求环的长度
int fastLength = 0;
int slowLength = 0;
int loopLength = 0;
//求出环的长度 通过这两个求出环的入口节点
SListNode* p1 = list;
SListNode* p2 = list;
while (1)
{
//在两个指针走之前必须判断pFast和pFast的next是否为空,两个条件都必须判断而且判断顺序不能出错
//因为快指针走得快,我们只需要判断快指针,如果为空,即链表不带环,返回NULL。
//检测是否带环同时也避免指针越界访问
if (NULL==pFast||NULL==pFast->_next)
return NULL;
pFast = pFast->_next->_next;
pSlow = pSlow->_next;
if (pFast==pSlow)
break;
}
//两指针相遇时 求环的长度
while (1)
{
pFast = pFast->_next->_next;
fastLength += 2;
pSlow = pSlow->_next;
++slowLength;
if (pFast==pSlow)
{
break;
}
}
loopLength = fastLength - slowLength;//求出环的长度
while (1)
{
//这里p1先走loopLength
for (int i = 0; i < loopLength; ++i)
{
p1 = p1->_next;
}
if (p1 == p2)
{
return p1;
}
//相同速度走
while (1)
{
p1 = p1->_next;
p2 = p2->_next;
//先走后判断防止刚开始是相等情况
//找到环的入口点
if (p1==p2)
{
return p1;
}
}
}
}
//12.判断两个链表是否相交,若相交,求交点。
//首先判断链表是否带环
SListNode* ListIsLoop(SListNode* list)
{
SListNode* pFast = list;
SListNode* pSlow = list;
while (pFast&&pFast->_next)
{
pFast = pFast->_next->_next;
pSlow = pSlow->_next;
if (pFast==pSlow)
{
return pSlow;//带环
}
}
return NULL;//不带环
}
//判断两个链表是否相交,若相交,求交点
SListNode* ListIsIntersect(SListNode* list1, SListNode* list2)
{
//有一个链表为空的情况
if (list1==NULL || list2==NULL)
{
return NULL;
}
SListNode* p1 = ListIsLoop(list1);
SListNode* p2 = ListIsLoop(list2);
//两个链表都带环的情况
//带环不相交问题
if (p1!=NULL&&p2!=NULL)
{
SListNode* cur = p2;
while (cur!=p1)
{
cur = cur->_next;
if (cur==p2) //cur走了一圈没有与p1相遇 说明不相交
{
return NULL;
}
}
//带环相交问题,一种交点在环上, 交点没在环上
//求环的入口点
SListNode* start1 = LoopStart(list1);
SListNode* start2 = LoopStart(list2);
if (start1==start2) //交点没在环上 可以转化成求无环链表的交点
{
SListNode* cur1 = list1;
SListNode* cur2 = list2;
while (cur1!=cur2)
{
if (cur1==start1)
{
cur1 = list2;
}
else
{
cur1 = cur1->_next;
}
if (cur1==start2)
{
cur2 = list1;
}
else
{
cur2 = cur2->_next;
}
}
return cur1;
}
else // 交点在环上,两个入口点都有可能是交点 随便返回一个
{
return start2;
}
}
//两个链表都没带环
else if (p1==NULL && p2==NULL)
{
SListNode* cur1 = list1;
SListNode* cur2 = list2;
while (cur1!=cur2)
{
if (cur1 == NULL)
cur1 = list2;
else
{
cur1 = cur1->_next;
}
if (cur2==NULL)
{
cur2 = list1;
}
else
{
cur2=cur2->_next;
}
}
return cur1;
}
//一个链表带环 一个链表不带环 他们肯定没有交点
else
{
return NULL;
}
}
//13.求两个已排序单链表中相同的数据。
SListNode* ByeNode(DataType data) // 建立新的节点
{
SListNode* pNewNode = (SListNode*)malloc(sizeof(struct SListNode));
if (NULL != pNewNode)
{
pNewNode->_data = data;
//注意使开辟的新节点的指向为空
pNewNode->_next = NULL;
}
return pNewNode;
}
SListNode* UnionSet(SListNode* l1, SListNode* l2)
{
SListNode* pList1 = l1;
SListNode* pList2 = l2;
SListNode* pNewHead = NULL;
SListNode* pNode = NULL;
//每次比较两个链表头指针指向的数据是否相等,不相等,就让数据小的头指针后移,相等,则把该数据保存起来,
//两个头指针同时后移,直到其中一个指向空为止
while ((NULL==pList1) || (NULL==pList2))
{
if (pList1->_data>pList2->_data)
{
pList2 = pList2->_next;
}
else if (pList1->_data<pList2->_data)
{
pList1 = pList1->_next;
}
//用一个新的链表来保存两个链表中的相同数据
else
{
if (pNewHead==NULL)
{
pNewHead = ByeNode(pList1->_data);
pNode = pNewHead;
pList1 = pList1->_next;
pList2 = pList2->_next;
}
else
{
pNode = pNode->_next;
pNode = pNewHead;
pList1 = pList1->_next;
pList2 = pList2->_next;
}
}
}
return pNewHead;
}