链表常见面试题总结:求两链表交点,链表插删,拼接,逆置…..
1从尾到头打印单链表
2.递归销毁一个链表
3.删除一个无头单链表的非尾节点(不能遍历链表)
4.在无头单链表的一个节点前插入一个节点(不能遍历链表)
5.单链表实现约瑟夫环(JosephCircle)
6.逆置/反转单链表
7.单链表排序(冒泡排序&快速排序)
8.合并两个有序链表,合并后依然有序
9.查找单链表的中间节点,要求只能遍历一次链表
10.查找单链表的倒数第k个节点,要求只能遍历一次链表
11.删除链表的倒数第K个结点
12.判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度。
13.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
14.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
15.求两个已排序单链表中相同的数据
/**********头文件************/
#pragma once
typedef int DataType;
typedef struct SListNode{
DataType _data;
struct SListNode* _pNext;
}Node,*PNode;
void SListInit(PNode* ppHead);
PNode BuyNode(DataType data);
void SListPushBack(PNode* ppHead, DataType data);
void SlistPushFront(PNode* ppHead, DataType data);
PNode FindNode(PNode pHead, DataType data);
void SListDestroy(PNode* ppHead);
void SListPrint(PNode pHead);
void TestSList();
/以下是面试题
void SListPrint_Reverse(PNode pHead);
void SListDestroy_R(PNode* ppHead);
void EraseNotTailNode(PNode* pos);
void InsertFrontNode(PNode pos,DataType data);
void JosephCircle(PNode* pHead, size_t n);
void TestJosephCircle();
void ReverseSList(PNode* ppHead);
void ReverseSList_New(PNode* ppHead);
void BubbleSortSList(PNode pHead);
PNode MergeSList(PNode pHead1, PNode pHead2);
PNode FindMiddleNode(PNode pHead);
PNode FindBackNode(PNode pHead, size_t K);
int DeleteBackNode(PNode* ppHead, size_t K);
PNode HasCircle(PNode pHead);
int GitCircleLen(PNode pHead);
PNode GitEntranceNode(PNode pHead);
int IsCross(PNode pHead1, PNode pHead2);
PNode GetCrossNode(PNode pHead1, PNode pHead2);
PNode GetCrossIsCircleNode(PNode pHead1, PNode pHead2);
void UnionSList(PNode pHead1, PNode pHead2);
/*****************代码*********************/
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "SList.h"
void SListInit(PNode* ppHead){
assert(ppHead);
*ppHead= NULL;
}
PNode BuyNode(DataType data){
PNode pNewNode = (PNode)malloc(sizeof(Node));
pNewNode->_data = data;
pNewNode->_pNext = NULL;
if (pNewNode == NULL){
printf("malloc error !!!\n");
return NULL;
}
return pNewNode;
}
void SListPushBack(PNode* ppHead, DataType data){
assert(ppHead);
if (*ppHead == NULL){
(*ppHead) = BuyNode(data);
}
else{
PNode pCur = *ppHead;
while (pCur->_pNext){
pCur = pCur->_pNext;
}
pCur->_pNext = BuyNode(data);
}
}
void SlistPushFront(PNode* ppHead, DataType data){
assert(ppHead);
PNode pNewNode = BuyNode(data);
pNewNode->_pNext = *ppHead;
*ppHead = pNewNode;
}
PNode FindNode(PNode pHead, DataType data){
assert(pHead);
if (NULL == pHead){
return NULL;
}
PNode pCur = pHead;
while(pCur){
if (pCur->_data == data){
return pCur;
}
pCur = pCur->_pNext;
}
return NULL;
}
void SListDestroy(PNode* ppHead){
assert(ppHead);
PNode pCur = *ppHead;
PNode pTmp = NULL;
while (pCur){
pTmp = pCur;
pCur = pCur->_pNext;
free(pTmp);
}
*ppHead = NULL;
}
void SListPrint(PNode pHead){
PNode pCur = pHead;
while (pCur){
printf("%d --> ", pCur->_data);
pCur = pCur->_pNext;
}
printf("NULL\n");
}
//
//1.从尾到头打印单链表
void SListPrint_Reverse(PNode pHead){
if (pHead){
SListPrint_Reverse(pHead->_pNext);
printf("%d --> ", pHead->_data);
}
}
//2.递归销毁一个链表(从后往前)
void SListDestroy_R(PNode* ppHead){
assert(ppHead);
if (*ppHead){
SListDestroy_R(&(*ppHead)->_pNext);
free(*ppHead);
*ppHead = NULL;
}
}
//3.删除一个无头单链表的非尾节点(不能遍历链表)
void EraseNotTailNode(PNode* pos){
assert(pos);
if (pos == NULL)
return;
(*pos) = (*pos)->_pNext;
}
//4.在无头单链表的一个节点前插入一个节点(不能遍历链表)
void InsertFrontNode(PNode pos,DataType data){
PNode pNewNode = NULL;
if (NULL == pos)
return;
pNewNode = BuyNode(pos->_data);
pNewNode->_pNext = pos->_pNext;
pos->_pNext = pNewNode;
pos->_data = data;
}
//5.单链表实现约瑟夫环(JosephCircle)
void JosephCircle(PNode* ppHead, size_t n){
assert(ppHead);
PNode pCur = *ppHead;
PNode pTmp = NULL;
while (pCur != pCur->_pNext){
size_t m = n;
while (--m){
pCur = pCur->_pNext;
}
pTmp = pCur->_pNext;
pCur->_pNext = pTmp->_pNext;
pCur->_data = pTmp->_data;
free(pTmp);
}
*ppHead = pCur;
}
//6.逆置/反转单链表
//三指针式
void ReverseSList(PNode* ppHead){
assert(ppHead);
if ((*ppHead) == NULL || NULL == (*ppHead)->_pNext){
return;
}
PNode p1 = (*ppHead);
PNode p2 = p1->_pNext;
p1->_pNext = NULL;
PNode p3 = NULL;
while (p2){
p3 = p2->_pNext;
p2->_pNext = p1;
p1 = p2;
p2 = p3;
}
*ppHead = p1;
}
//头插式
void ReverseSList_New(PNode* ppHead){
assert(ppHead);
if (NULL == *ppHead || NULL == (*ppHead)->_pNext){
return;
}
PNode pNewNode = NULL;
PNode pCur = *ppHead;
PNode pNext = NULL;
while (pCur){
pNext = pCur->_pNext;
pCur->_pNext = pNewNode;
pNewNode = pCur;
pCur = pNext;
}
*ppHead = pNewNode;
}
//7.单链表排序(冒泡排序)
void Swap(DataType* a, DataType* b){
DataType tmp = *a;
*a = *b;
*b = tmp;
}
void BubbleSortSList(PNode pHead){
assert(pHead);
if (NULL == pHead || NULL == pHead->_pNext){
return;
}
int flag = 1;
PNode pCur = NULL;
PNode pTmp = NULL;
PNode pTail = NULL;
while (pHead != pTail){
flag = 1;
pCur = pHead;
pTmp = pCur->_pNext;
while (pTmp != pTail){
flag = 0;
if (pCur->_data > pTmp->_data){
Swap(&(pCur->_data),& (pTmp->_data));
}
pCur = pTmp;
pTmp = pTmp->_pNext;
}
if (flag){
return;
}
pTail = pCur;
}
return;
}
//8.合并两个有序链表,合并后依然有序
PNode MergeSList(PNode pHead1, PNode pHead2){
assert(pHead1);
assert(pHead2);
if (pHead1 == NULL){
return pHead2;
}
if (pHead2 == NULL){
return pHead1;
}
PNode p1 = pHead1;
PNode p2 = pHead2;
PNode pNewNode = NULL;
PNode pTail = NULL;
if (p1->_data > p2->_data){
pNewNode = p2;
p2 = p2->_pNext;
}
else{
pNewNode = p1;
p1 = p1->_pNext;
}
pTail = pNewNode;
while (p1 && p2){
if (p1->_data > p2->_data){
pTail->_pNext = p2;
p2 = p2->_pNext;
}
else{
pTail->_pNext = p1;
p1 = p1->_pNext;
}
pTail = pTail->_pNext;
}
if (p1 == NULL){
pTail->_pNext = p2;
}
if (p2 == NULL){
pTail->_pNext = p1;
}
return pNewNode;
}
//9.查找单链表的中间节点,要求只能遍历一次链表
PNode FindMiddleNode(PNode pHead){
PNode pSlow = pHead;
PNode pFast = pHead;
while(pFast && pFast->_pNext){
pSlow = pSlow->_pNext;
pFast = pFast->_pNext->_pNext;
}
return pSlow;
}
//10.查找单链表的倒数第k个节点,要求只能遍历一次链表
PNode FindBackNode(PNode pHead,size_t K){
assert(pHead);
if (pHead == NULL || K == 0){
return NULL;
}
PNode pFast = pHead;
PNode pSlow = pHead;
while (--K){
if (pFast == NULL){
return NULL;
}
pFast = pFast->_pNext;
}
while (pFast->_pNext){
pFast = pFast->_pNext;
pSlow = pSlow->_pNext;
}
return pSlow;
}
//11.删除链表的倒数第K个结点
int DeleteBackNode(PNode* ppHead, size_t K){
assert(ppHead);
if (*ppHead == NULL || K == 0){
return 0;
}
PNode pSlow = *ppHead;
PNode pFast = *ppHead;
PNode pStr = NULL;
while (--K){
if (pFast == NULL){
return 0;
}
pFast = pFast->_pNext;
}
while (pFast->_pNext){
pStr = pSlow;
pSlow = pSlow->_pNext;
pFast = pFast->_pNext;
}
if (pSlow == *ppHead){
*ppHead = pSlow->_pNext;
}
else{
pStr->_pNext = pSlow->_pNext;
}
free(pSlow);
return 1;
}
//12.判断单链表是否带环?若带环,求环的长度?求环的入口点?
// 并计算每个算法的时间复杂度&空间复杂度
PNode HasCircle(PNode pHead){
assert(pHead);
if (pHead == NULL){
return NULL;
}
PNode pSlow = pHead;
PNode pFast = pHead;
while (pFast && pFast->_pNext){
pSlow = pSlow->_pNext;
pFast = pFast->_pNext->_pNext;
if (pSlow == pFast){
return pSlow;
}
}
return NULL;
}
//求环的长度
int GitCircleLen(PNode pHead){
PNode pMeet = HasCircle(pHead);
if (pMeet == NULL){
return 0;
}
int count = 0;
PNode pCur = pMeet->_pNext;
while (pCur != pMeet){
count++;
pCur = pCur->_pNext;
}
count++;
return count;
}
//找环的入口节点 时间复杂度:O(N)
PNode GitEntranceNode(PNode pHead){
PNode pMeet = HasCircle(pHead);
PNode pCur = pHead;
while (pCur != pMeet){
pCur = pCur->_pNext;
pMeet = pMeet->_pNext;
}
return pMeet;
}
//13.判断两个链表是否相交,若相交,求交点。(假设链表不带环)
int IsCross(PNode pHead1, PNode pHead2){
assert(pHead1);
assert(pHead2);
if (pHead1 == NULL || NULL == pHead2){
return 0;
}
PNode p1 = pHead1;
PNode p2 = pHead2;
while (p1->_pNext){ //最后一个节点
p1 = p1->_pNext;
}
while (p2->_pNext){
p2 = p2->_pNext;
}
if (p1 == p2){
return 1;
}
return 0;
}
//求不带环的交点
PNode GetCrossNode(PNode pHead1, PNode pHead2){
if (!IsCross(pHead1, pHead2)){
return NULL;
}
PNode p1 = pHead1;
PNode p2 = pHead2;
int n1 = 1;
int n2 = 1;
int n = 0;
while (p1->_pNext){
n1++;
p1 = p1->_pNext;
}
while (p2->_pNext){
n2++;
p2 = p2->_pNext;
}
n = n1 - n2;
p1 = pHead1;
p2 = pHead2;
if (n > 0){
while (n--){
p1 = p1->_pNext;
}
}
else{
while (n++){
p2 = p2->_pNext;
}
}
while (p1 != p2){
p1 = p1->_pNext;
p2 = p2->_pNext;
}
return p1;
}
//14.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
//此题用到12,13题的部分函数,可分列出来
PNode GetCrossIsCircleNode(PNode pHead1, PNode pHead2){
assert(pHead1);
assert(pHead2);
if (pHead1 == NULL || pHead2 == NULL){
return NULL;
}
PNode p1 = HasCircle(pHead1);//存在环,返回值为快慢指针环相遇值 Meet
PNode p2 = HasCircle(pHead2);
PNode pCur = NULL;
if (p1 == NULL && p2 == NULL){ //两个都不带环
pCur = GetCrossNode(pHead1, pHead2);
return pCur;
}
else if (p1 && p2){//两个都是带环链表
PNode pTmp = p1;
while (p1 != p2){ //若两带环相交,环比为其公共 故可判断p1 p2是否在同一环 判断是否相交
p1 = p1->_pNext;
if (p1 == pTmp){ //转过一圈 不存在
return NULL;
}
}//出while 存在
//存在又分为环内交点和环外交点(环内交点 整个环都是 此处返回两个入口点)
//通过两个带环链表的入口点是否相等,判断环内还是环外相交
PNode pMeet1 = GitEntranceNode(pHead1);
PNode pMeet2 = GitEntranceNode(pHead2);
if (pMeet1 == pMeet2){
pTmp = p1->_pNext;//准备破环变链求交点 备份
//不破环也能求交点 破环更容易 直接调链式相交点函数
//不破环可将链式求交点函数(GetCrossNode)中的计数两链表长度中的条件NULL改成环上任意一点(p1,p2)
p1->_pNext = NULL;
pCur = GetCrossNode(pHead1, pHead2);
//既然有交点 一定有返回值 若空 只能说太巧破环破在(0,6模型)入换点
//破环已经损坏原有链表 此处拿到pCur后,还原链表
p1->_pNext = pTmp;
if (pCur){
return pCur;
}
else{//破环点刚好是环入口点 交点 (0 6 模型)
return pTmp;
}
}
else{
return pMeet1;//整个环都是交点 随便返回环上一点 建议两个入口点中选
}
}//else if
else{//一环一链肯定无交点
return NULL;
}
}
//15.求两个已排序单链表中相同的数据。
void UnionSList(PNode pHead1, PNode pHead2){
assert(pHead1);
assert(pHead2);
if (pHead1 == NULL || pHead2 == NULL){
return;
}
PNode p1 = pHead1;
PNode p2 = pHead2;
int tmp = 0;
int flag = 1;
while (p1 && p2){
if (p1->_data < p2->_data){
p1 = p1->_pNext;
}
else if (p1->_data > p2->_data){
p2 = p2->_pNext;
}
else{
if ((tmp != p1->_data) || flag){
printf("%d ", p1->_data);
}
p1 = p1->_pNext;
p2 = p2->_pNext;
flag = 0; //防止tmp的初始值与两个链表的第一次相同值相等
}
}
printf("\n");
return;
}
/************************************************************************************/
//测试5题
void TestJosephCircle()
{
PNode s;
PNode pTail;
SListInit(&s);
SListPushBack(&s, 1);
SListPushBack(&s, 2);
SListPushBack(&s, 3);
SListPushBack(&s, 4);
SListPushBack(&s, 5);
SListPushBack(&s, 6);
SListPushBack(&s, 7);
pTail = FindNode(s, 7);
pTail->_pNext = s;
JosephCircle(&s, 3);
printf("result = %d\n", s->_data);
}
//测12题
void TestCircle(){
PNode s;
SListInit(&s);
SListPushBack(&s, 1);
SListPushBack(&s, 2);
SListPushBack(&s, 3);
SListPushBack(&s, 4);
SListPushBack(&s, 5);
SListPushBack(&s, 6);
SListPushBack(&s, 7);
SListPushBack(&s, 8);
SListPushBack(&s, 9);
SListPushBack(&s, 0);
FindNode(s, 0)->_pNext = FindNode(s, 4);
//FindNode(s, 0)->_pNext = s;
printf("Meet = %d \n", HasCircle(s)->_data);
printf("Len = %d\n", GitCircleLen(s));
printf("Entrance Node = %d\n", GitEntranceNode(s)->_data);
}
//测13题
void TestCross(){
PNode s;
SListInit(&s);
SListPushBack(&s, 4);
SListPushBack(&s, 6);
SListPushBack(&s, 1);
SListPushBack(&s, 5);
SListPushBack(&s, 3);
SListPushBack(&s, 2);
PNode L;
SListInit(&L);
SListPushBack(&L, 0);
SListPushBack(&L, 1);
SListPushBack(&L, 6);
SListPushBack(&L, 4);
SListPushBack(&L, 7);
SListPushBack(&L, 8);
SListPushBack(&L, 9);
FindNode(s, 2)->_pNext = FindNode(L, 6);
printf("IsCross = %d\n", IsCross(L, s));
//printf("CrossNode = %d\n", GetCrossNode(L, s)->_data);
//printf("CrossNode = %d\n", GetCrossIsCircleNode(L, s)->_data);//测14 双链
}
//测14题
void TestNotKnowCircle(){
//造环
PNode s;
SListInit(&s);
SListPushBack(&s, 1);
SListPushBack(&s, 2);
SListPushBack(&s, 3);
SListPushBack(&s, 4);
SListPushBack(&s, 5);
SListPushBack(&s, 6);
SListPushBack(&s, 7);
SListPushBack(&s, 8);
PNode L;
SListInit(&L);
SListPushBack(&L, 0);
SListPushBack(&L, 1);
PNode pCur = NULL;
//结束
FindNode(s, 8)->_pNext = FindNode(s, 4);
FindNode(L, 1)->_pNext = FindNode(s, 2);
pCur = GetCrossIsCircleNode(s, L);//双环(6,6)模型
//FindNode(s, 8)->_pNext = FindNode(s, 4);
//pCur = GetCrossIsCircleNode(s, FindNode(s, 4));//双环(0,6)模型
if (pCur){
printf("Circle = %d\n", pCur->_data);
}
else{
printf("不存在!!!\n");
}
}
//测15题
void TestUnion(){
PNode s;
SListInit(&s);
SListPushBack(&s, 1);
SListPushBack(&s, 1);
SListPushBack(&s, 2);
SListPushBack(&s, 4);
SListPushBack(&s, 5);
SListPushBack(&s, 8);
PNode L;
SListInit(&L);
SListPushBack(&L, 1);
SListPushBack(&L, 1);
SListPushBack(&L, 3);
SListPushBack(&L, 4);
SListPushBack(&L, 7);
SListPushBack(&L, 8);
SListPushBack(&L, 9);
UnionSList(s, L);
}
//主测试
void TestSList(){
PNode s;
SListInit(&s);
SListPushBack(&s, 4);
SListPushBack(&s, 6);
SListPushBack(&s, 1);
SListPushBack(&s, 5);
SListPushBack(&s, 3);
SListPushBack(&s, 2);
PNode L;
SListInit(&L);
SListPushBack(&L, 0);
SListPushBack(&L, 1);
SListPushBack(&L, 1);
SListPushBack(&L, 4);
SListPushBack(&L, 7);
SListPushBack(&L, 8);
SListPushBack(&L, 9);
//SListPrint(s);
//SlistPushFront(&s,0);
//SListPrint(s);
//printf("Find = %d\n",FindNode(s,6)->_data);
//SListPrint_Reverse(s);
//EraseNotTailNode(&(s->_pNext->_pNext->_pNext));
//SListDestroy(&s);
//SListPrint(s);
//InsertFrontNode((s->_pNext),9);
//SListPrint(s);
//TestJosephCircle();
//ReverseSList(&s);
//SListPrint(s);
//ReverseSList_New(&s);
SListPrint(s);
BubbleSortSList(s);
SListPrint(s);
printf("Middle = %d\n", FindMiddleNode(s)->_data);
printf("BackNode = %d\n",FindBackNode(s, 3)->_data);
printf("IsDelete = %d\n", DeleteBackNode(&s, 3));
SListPrint(s);
//SListPrint(MergeSList(s,L));
//TestCircle();
//TestCross();
//TestNotKnowCircle();
TestUnion();
SListDestroy_R(&s);
}
int main(){
TestSList();
return 0;
}
带头节点的双向链表:
https://blog.csdn.net/Romantic_C/article/details/79991268
带头节点的单链表:
https://blog.csdn.net/Romantic_C/article/details/79919836