C语言单链表的实现及其面试题—完整代码

相关博客链接:

C语言实现 单向链表
https://blog.csdn.net/qq_37941471/article/details/72961495
C语言实现单链表面试题—基础篇
https://blog.csdn.net/qq_37941471/article/details/78033970
C语言实现单链表面试题—进阶
https://blog.csdn.net/qq_37941471/article/details/80437143


代码:

List.h List.c test.c

  • List.h :
#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#include <assert.h>

typedef int DataType;
typedef struct ListNode
{
    DataType data;//节点存放的数据
    struct ListNode* next;//下一个节点
}ListNode;


ListNode* BuyNode(DataType x);//创建节点
void PrintList(ListNode *plist);//打印链表

void PushBack(ListNode **pplist,DataType x);//尾插
void PopBack(ListNode **pplist);//尾删

void PushFront(ListNode **pplist,DataType x);//头插
void PopFront(ListNode **pplist);//头删

ListNode* Find(ListNode *plist,DataType x);//查找x

void Insert(ListNode **pplist,ListNode* pos,DataType x);//在pos位置前面插入节点
void Erase(ListNode **pplist,ListNode *pos);//删除pos节点

void PrintTailToHead(ListNode *plist);//2.从尾到头打印单链表 
void EraseNonTail(ListNode* pos);//3.删除一个无头单链表的非尾节点 
void InsertNonHead(ListNode* pos,DataType x);//4.在无头单链表的一个节点前插入一个节点 
ListNode* JosepRing(ListNode* list,DataType k);//5.单链表实现约瑟夫环
void Reverse(ListNode** pplist);//6.翻转/逆置链表
void SortList(ListNode* list);//7.单链表排序(冒泡排序)
ListNode* Merge(ListNode* list1,ListNode* list2);//8.合并两个有序单链表,合并后依然有序
ListNode* FindMidNode(ListNode* plist);//9.查找链表的中间节点,要求只能遍历一次
void FindKNode(ListNode* plist,int k);//10.查找单链表的倒数第k个节点,要求只能遍历一次

ListNode* IsCycle(ListNode* plist);//11.判断链表是否带环?
ListNode* GetEntry(ListNode* plist, ListNode* MeetNode);//若带环,求其入口点
int GetCycle_Length(ListNode* MeetNode);//若带环,求环的长度

int IsCross_NoCycle(ListNode* plist1,ListNode* plist2);//12.判断两个链表是否相交?(假设链表不带环)
ListNode* GetCrossNode(ListNode* plist1, ListNode* plist2);//若相交,求交点

ListNode* IsCross_Cycle(ListNode* plist1,ListNode* plist2);//13.判断两个链表是否相交?若相交,求交点。(假设链表可能带环)


  • List.c :
#include "List.h"

ListNode* BuyNode(DataType x)//创建节点
{
    ListNode* Node = (ListNode*)malloc(sizeof(ListNode));//开辟空间
    Node->data = x;
    Node->next = NULL;
    return Node;
}

void PrintList(ListNode *plist)//打印链表
{
    ListNode* cur = plist;
    while (cur)
    {
        printf("%d->",cur->data);
        cur = cur->next ;
    }
    printf("NULL\n");
}

void PushBack(ListNode **pplist,DataType x)//尾插
{
    assert(pplist);
    //1. 链表为空
    //2. 一个节点
    //3. 多个节点

    if( *pplist == NULL )
    {
        *pplist = BuyNode(x);
    }
    else if( (*pplist)->next == NULL )
    {
        (*pplist)->next = BuyNode(x);
    }
    else //多节点
    {
        ListNode* cur = *pplist;
        while ( cur->next ) //终止条件(找最后一个节点):cur->next == NULL;所以继续条件恰好相反
        {
            cur = cur->next ;
        }
        cur->next = BuyNode(x);
    }
}

void PopBack(ListNode **pplist)//尾删
{
    assert(pplist);
    //1. 链表为空
    //2. 一个节点
    //3. 多个节点
    if( *pplist == NULL )
        return;
    else if( (*pplist)->next == NULL )
    {
        free(*pplist);//malloc free()
        *pplist = NULL;
    }
    else//多节点
    {
        ListNode* prev = *pplist;
        ListNode* cur = *pplist;
        while( cur->next )
        {
            prev = cur;
            cur = cur->next ;
        }
        free(cur);
        cur = NULL;
        prev->next = NULL;
    }
}

void PushFront(ListNode **pplist,DataType x)//头插
{
    assert(pplist);
    //1. 链表为空
    //2. 非空
    if( *pplist == NULL )
    {
        *pplist = BuyNode(x);
    }
    else //非空 
    {
        ListNode* Node = BuyNode(x);
        Node->next = *pplist;
        *pplist = Node;
    }
}

void PopFront(ListNode **pplist)//头删
{
    assert(pplist);
    //1. 链表为空
    //2. 一个节点
    //3. 多节点
    if( *pplist == NULL )
        return;
    else if ( (*pplist)->next == NULL )
    {
        free(*pplist);
        *pplist = NULL;
    }
    else//多节点
    {
        ListNode* tmp  = *pplist;
        ListNode* Next = (*pplist)->next ;
        *pplist = Next;
        free(tmp);
    }
}

ListNode* Find(ListNode *plist,DataType x)//查找x
{
    assert(plist);
    while( plist )
    {
        if( plist->data == x )
            return plist;
        plist = plist->next ;
    }
    return NULL;
}

void Insert(ListNode **pplist,ListNode* pos,DataType x)//在pos位置前面插入节点
{
    assert(pplist&&pos);
    //1. pos为头结点,则进行头插
    //2. pos为其他节点
    if( *pplist == pos )//pos为头结点
    {
        PushFront(pplist,x);
    }
    else //pos为其他节点
    {
        ListNode* tmp = BuyNode(x);
        ListNode* prev = *pplist ;
        ListNode* cur = *pplist;
        //while( cur )
        //{
        //  if( cur->next == pos )//找pos的prev
        //      prev = cur;
        //  cur = cur->next ;
        //}
        while( prev->next != pos )//终止条件:prev->next == pos,则找到了prev
        {
            prev = prev->next ;
        }
        prev->next = tmp;
        tmp->next = pos;
    }
}

void Erase(ListNode **pplist,ListNode *pos)//删除pos节点
{
    assert(pplist&&pos);
    //1. 头删
    //2. 尾删
    //3. 中间删
    if( *pplist == pos )//头删
    {
        PopFront(pplist);
    }
    else if( pos->next == NULL ) //尾删
    {
        PopBack(pplist);
    }
    else //中间删
    {
        ListNode* prev = *pplist;
        while( prev->next != pos )
        {
            prev = prev->next ;
        }
        prev->next = pos->next ;
        free(pos);
        pos = NULL;
    }
}

void PrintTailToHead(ListNode *plist)//2.从尾到头打印单链表
{
    if( plist == NULL )
        return;
    PrintTailToHead(plist->next);
    printf("%d ",plist->data);
}

void EraseNonTail(ListNode* pos)////3.删除一个无头单链表的非尾节点 
{
    //1 2 3 4 
    //3
    //删除一个无头非尾节点,即将目标节点3的下一个节点next4的值赋给3所在的位置,然后将pos->next指向next->next,并释放next
    ListNode* Next = pos->next ;
    assert(pos&&Next);//断言Next不为空  因为是一个非尾节点
    pos->data = Next->data ;
    pos->next = Next->next ;
    free(Next);
}

void InsertNonHead(ListNode* pos,DataType x)//4.在无头单链表的一个节点前插入一个节点 
{
    //1 2 3 5
    //5前面加4
    //创建新的节点tmp,给其data为5,然后将5的节点的(pos)next指向tmp,将tmp->next 指向 next,最后将5改成x(4)
    ListNode* Next = NULL;
    ListNode* tmp = BuyNode( pos->data );
    assert(pos);
    Next = pos->next ;
    pos->next = tmp;
    tmp->next = Next;
    pos->data = x;
}

ListNode* JosepRing(ListNode* list,DataType k)//5.单链表实现约瑟夫环
{
    int count = k;
    ListNode* cur = list;
    ListNode* prev = NULL;
    assert(list);
    if (NULL == list)
        return NULL;
    while ( cur->next != cur )//终止条件:cur->next == cur(只剩下一个节点)
    {
        count = k;
        while (--count)
        {
            prev = cur;
            cur = cur->next ;
        }
        //走到这里就开始删除,然后继续循环    
        printf ("删除第%d个人 \n",cur->data);
        prev->next = cur->next ;
        free(cur);
        cur = prev->next ;
    }
    return cur;
}

void Reverse(ListNode** pplist)//6.翻转/逆置链表
{
    ListNode* prev = *pplist;
    ListNode* cur = prev->next ;
    ListNode* Next = NULL;
    assert(pplist);
    //1. 空链表和只有一个节点 都不需要逆置
    //2. 多节点 逆置
    if( *pplist == NULL || ((*pplist)->next == NULL) )
    {
        return;
    }
    //逆置
    while(cur)
    {
        Next = cur->next ;
        cur->next = prev;
        prev = cur;
        cur = Next;
    }
    (*pplist)->next = NULL;
    *pplist = prev ;
}

void SortList(ListNode* list)//7.单链表排序(冒泡排序)
{
    ListNode* cur = list;
    ListNode* next = cur->next ;
    ListNode* tail = NULL;
    int exchange = 0;
    assert(list);
    if( list == NULL || (list->next == NULL) )
    {
        return;
    }
    tail = NULL;
    cur = list;
    next = cur->next ;
    while( cur != tail )
    {
        while( next != tail )
        {
            if( cur->data > next->data )
            {
                DataType tmp = cur->data ;
                cur->data = next->data ;
                next->data = tmp;
                exchange = 1;
            }
            cur = cur->next ;
            next = next->next ;
        }
        if( 0 == exchange )
        {
            break;
        }
        tail = cur;
        cur = list;
        next = cur->next ;
    }
}

ListNode* Merge(ListNode* list1,ListNode* list2)//8.合并两个有序单链表,合并后依然有序
{
    ListNode* list = NULL;
    ListNode* cur ;
    assert(list1&&list2);
    //1. list1空链表
    //2. list2空链表
    //3. 都非空
    if( list1 == NULL )
        return list2;
    if( list2 == NULL )
        return list1;
    if( list1->data > list2->data  )
    {
        list = list2;
        list2 = list2->next ;
    }
    else
    {
        list = list1;
        list1 = list1->next ;
    }
    cur = list;
    while( list1&&list2 )
    {
        if( list1->data > list2->data )
        {
            cur->next = list2;
            cur = cur->next ;
            list2 = list2->next ;
        }
        else
        {
            cur->next = list1;
            cur = cur->next ;
            list1 = list1->next ;
        }
    }
    if( list1 == NULL )
        cur->next = list2;
    if( list2 == NULL )
        cur->next = list1;
    return list;
}
ListNode* FindMidNode(ListNode* plist)//9.查找链表的中间节点,要求只能遍历一次
{
    ListNode* slow = plist;
    ListNode* fast = plist;
    /*assert(plist);*/
    if( plist == NULL )
        return NULL;
    while( fast && (fast->next) && (fast->next->next) )
    {
        fast = fast->next->next ;
        slow = slow->next ;
    }
    return slow;
}
void FindKNode(ListNode* plist,int k)//10.查找单链表的倒数第k个节点,要求只能遍历一次
{
    ListNode* slow = plist;
    ListNode* fast = plist;
    int count = k;
    assert(plist);
    if( plist == NULL )
        return;
    while( fast && (fast->next) )
    {
        if( --count > 0)
        {
            fast = fast->next;
        }
        fast = fast->next ;
        slow = slow->next ;
        /*fast = fast->next ;
        if( --count <= 0 )
        {
            slow = slow->next ;
        }*/
    }
    printf("倒数第%d个数是%d\n",k,slow->data);
}

ListNode* IsCycle(ListNode* plist)//11.判断链表是否带环?
{
    ListNode* slow = plist;
    ListNode* fast = plist;
    if( plist == NULL || plist->next == NULL )
            return NULL;
    while( fast && fast->next )//如果不带环,快指针先走到尾(终止条件)
    {
        fast = fast->next->next;
        slow = slow->next;
        if( slow == fast )//如果带环,快慢指针一定会相遇
            return slow;
    }
    return NULL;
}

ListNode* GetEntry(ListNode* plist, ListNode* MeetNode)//若带环,求其入口点。
{
    assert( plist&&MeetNode);
    while( plist != MeetNode )//plist == MeetNode找到入口点
    {
        plist = plist->next ;
        MeetNode = MeetNode->next ;
    }
    return plist;
}

int GetCycle_Length(ListNode* MeetNode)//若带环,求环的长度
{
    ListNode* cur = MeetNode->next ;
    int num = 1;
    while( cur != MeetNode )
    {
        ++num;
        cur = cur->next;
    }
    return num;
}

int IsCross_NoCycle(ListNode* plist1,ListNode* plist2)//12.判断两个链表是否相交?(假设链表不带环)
{
    assert(plist1&&plist2);
    if( plist1 == NULL || plist2 == NULL )
        return -1;
    while(plist1->next)
    {
        plist1 = plist1->next ;
    }
    while(plist2->next)
    {
        plist2 = plist2->next;
    }
    if( plist1 == plist2 )
        return 1;
}
ListNode* GetCrossNode(ListNode* plist1, ListNode* plist2)//若相交,求交点
{
    ListNode* longlist = plist1,*cur1 = plist1;
    ListNode* shortlist = plist2,*cur2 = plist2;
    int len1 = 0,len2 = 0;
    int gap;
    //求两个链表的长度,判断哪个长?
    while(cur1)
    {
        len1++;
        cur1 = cur1->next;
    }
    while(cur2)
    {
        len2++;
        cur2 = cur2->next;
    }
    if( len1<len2 )
    {
        longlist = plist2;
        shortlist = plist1;
    }
    gap = abs(len1-len2);
    //长的先走gap步,gap--(gap步),--gap(gap-1步)
    while(gap--)
    {
        longlist = longlist->next ;
    }
    //一起走,相遇点就是交点
    while( longlist != shortlist )
    {
        longlist = longlist->next ;
        shortlist = shortlist->next ;
    }
    return shortlist;
}

ListNode* IsCross_Cycle(ListNode* plist1,ListNode* plist2)//13.判断两个链表是否相交?若相交,求交点。(假设链表可能带环)
{
    //求链表带环的相遇点
    ListNode* MeetNode1 = IsCycle(plist1) ;
    ListNode* MeetNode2 = IsCycle(plist2) ;
    ListNode* entry1 ;
    ListNode* entry2 ;
    ListNode* meet,*cur1;
    //判断链表是否带环
    if( MeetNode1 == NULL || MeetNode2 == NULL )
        return NULL;//其中一个链表不带环,则不会相交,返回NULL
    //两个链表都带环,相交的两种情况
    //1.相同的入口点
    //2.不同的入口点
    entry1 = GetEntry(plist1,MeetNode1);
    entry2 = GetEntry(plist2,MeetNode2);
    if( entry1 == entry2 )//相同的入口点,返回交点
    {
        entry1->next = NULL;
        entry2->next = NULL;
        meet = GetCrossNode(plist1,plist2);
        return meet;
    }
    //不同的入口点的情况(判断条件:从MeetNode1开始遍历链表,如果找到和MeetNode2相等的节点,则证明共用环)
    //如果相交,返回任意一个入口点
    cur1 = MeetNode1->next ;
    while( cur1 != MeetNode1 && cur1 != MeetNode2 )
    {
        cur1 = cur1->next ;
    }
    if( cur1 == MeetNode2 )
        return entry1;
    return NULL;//不相交
}

  • test.c :
#include "List.h"

void test1()
{
    ListNode* list = NULL;

    PushBack(&list,1);
    PushBack(&list,2);
    PushBack(&list,3);
    PushBack(&list,4);
    PrintList(list);

    PopBack(&list);//尾删
    PrintList(list);

    PopBack(&list);
    PopBack(&list);
    PopBack(&list);
    PopBack(&list);//一个节点
    PrintList(list);

    PopBack(&list);
    PopBack(&list);
    PopBack(&list);
    PopBack(&list);
    PopBack(&list);//空链表
    PrintList(list);
}

void test2()
{
    ListNode* list = NULL;

    PushFront(&list,4);
    PushFront(&list,3);
    PushFront(&list,2);
    PushFront(&list,1);
    PrintList(list);

    PopFront(&list);//尾删
    PrintList(list);

    PopFront(&list);
    PopFront(&list);
    PopFront(&list);
    PopFront(&list);//一个节点
    PrintList(list);

    PopFront(&list);
    PopFront(&list);
    PopFront(&list);
    PopFront(&list);
    PopFront(&list);//空链表
    PrintList(list);
}

void test3()
{
    ListNode* list = NULL;
    ListNode* pos;

    PushFront(&list,4);
    PushFront(&list,3);
    PushFront(&list,2);
    PushFront(&list,1);
    PrintList(list);

    /*pos = Find(list,1);
    Insert(&list,pos,0);
    PrintList(list);*/

    /*pos = Find(list,1);
    Insert(&list,pos,0);
    PrintList(list);*/

    pos = Find(list,3);//找不到时返回NULL,则变成了尾插
    Insert(&list,pos,0);
    PrintList(list);

    Erase(&list,pos);
    PrintList(list);
}

void test4()
{
    ListNode* list = NULL;
    ListNode* pos;

    PushFront(&list,4);
    PushFront(&list,3);
    PushFront(&list,2);
    PushFront(&list,1);
    PrintTailToHead(list);
    printf("\n");

    /*pos = Find(list,2);
    EraseNonTail(pos);
    PrintList(list);*/

    pos = Find(list,4);//非尾节点,而4是尾节点
    EraseNonTail(pos);
    PrintList(list);
}

void test5()
{
    ListNode* list = NULL;
    ListNode* pos;

    PushFront(&list,4);
    PushFront(&list,3);
    PushFront(&list,1);
    PrintList(list);

    pos = Find(list,3);
    InsertNonHead(pos,2);
    PrintList(list);
}

void test6()
{
    ListNode* list = NULL;
    ListNode* tail ;
    ListNode* man;
    PushBack(&list,1);
    PushBack(&list,2);
    PushBack(&list,3);
    PushBack(&list,4);
    PushBack(&list,5);
    PushBack(&list,6);
    PushBack(&list,7);
    PushBack(&list,8);
    PrintList(list);

    tail = Find(list,8);
    tail->next = list;

    man =  JosepRing(list,3);

    printf("幸存者:%d \n",man->data);

}
void test7()
{
    ListNode* list = NULL;

    PushFront(&list,6);
    PushFront(&list,4);
    PushFront(&list,8);
    PushFront(&list,1);
    PrintList(list);

    //Reverse(&list);
    SortList(list);
    PrintList(list);
}

void test8()
{
    ListNode* list1 = NULL;
    ListNode* list2 = NULL;
    ListNode* list = NULL;
    //ListNode* mid;
    PushBack(&list1,1);
    PushBack(&list1,2);
    PushBack(&list1,5);
    PushBack(&list1,7);
    PrintList(list1);

    PushBack(&list2,3);
    PushBack(&list2,4);
    PushBack(&list2,8);
    PushBack(&list2,9);
    PrintList(list2);

    list =  Merge(list1,list2);
    PrintList(list);
}

void test9()
{
    ListNode* list = NULL;
    ListNode* mid;

    PushFront(&list,4);
    PushFront(&list,3);
    PushFront(&list,2);
    PushFront(&list,1);
    PrintList(list);

    mid = FindMidNode(list);
    printf("中间节点是%d\n",mid->data);
    FindKNode(list,2);
    PrintList(list);
}

void test10()
{
    ListNode* list = NULL;
    ListNode* tail;
    ListNode* entry;//入口点
    ListNode* meet;//相遇点
    int length ;

    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    PushBack(&list, 6);
    PrintList(list);

    tail = Find(list, 6);
    entry = Find(list, 4);
    tail->next = entry;//带环

    meet = IsCycle(list);
    printf("入口点:%d\n", GetEntry(list, meet)->data);

    length = GetCycle_Length(meet);
    printf("环的长度为%d\n",length);
}

void test11()
{
    ListNode* cross, *tail;
    ListNode* list1 = NULL;
    ListNode* list2 = NULL;

    PushBack(&list1, 1);
    PushBack(&list1, 2);
    PushBack(&list1, 3);
    PrintList(list1);

    PushBack(&list2, 4);
    PushBack(&list2, 5);
    PushBack(&list2, 6);
    PushBack(&list2, 7);
    PushBack(&list2, 8);
    PushBack(&list2, 9);
    PrintList(list2);

    cross = Find(list2, 8);
    tail = Find(list1, 3);
    tail->next = cross;

    //判断两个链表是否相交?
    if( 1 == IsCross_NoCycle(list1,list2) )
        printf("两个链表相交,");
    //求交点
    printf("交点是:%d\n", GetCrossNode(list1, list2)->data);
}

void test12()//判断两个链表是否相交?相同的入口点
{
    ListNode* cross, *tail1,*tail2;
    ListNode* entry;
    ListNode* list1 = NULL;
    ListNode* list2 = NULL;
    ListNode* meet;

    PushBack(&list1, 1);
    PushBack(&list1, 2);
    PushBack(&list1, 3);
    PrintList(list1);

    PushBack(&list2, 4);
    PushBack(&list2, 5);
    PushBack(&list2, 6);
    PushBack(&list2, 7);
    PushBack(&list2, 8);
    PushBack(&list2, 9);
    PushBack(&list2, 10);
    PushBack(&list2, 11);
    PrintList(list2);

    cross = Find(list2, 8);//交点
    tail1 = Find(list1, 3);
    tail1->next = cross;

    tail2 = Find(list2, 11);
    entry = Find(list2, 9);//入口点
    tail2->next = entry;//带环
    meet = IsCross_Cycle(list1,list2);
    printf("交点是:%d\n",meet->data);
}
int main()
{
    //test1();//尾插 尾删
    //test2();//尾插 尾删
    //test3();//查找K pos前插入节点 删除pos节点

    //test4();//2.从尾到头打印单链表 3.删除一个无头单链表的非尾节点 
    //test5();//4.在无头单链表的一个节点前插入一个节点 
    //test6();//5.单链表实现约瑟夫环
    //test7();//6.翻转/逆置链表  7.单链表排序(冒泡排序)
    //test8();//8.合并两个有序单链表,合并后依然有序
    //test9();//9.查找链表的中间节点,要求只能遍历一次 10.查找单链表的倒数第k个节点,要求只能遍历一次

    //test10();//11.判断单链表是否带环?若带环,求环的入口点;若带环,求环的长度
    //test11();//12.判断两个链表是否相交?若相交,求交点(假设链表不带环)
    test12();//13.判断两个链表是否相交?若相交,求交点。(假设链表可能带环)
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37941471/article/details/80458397
今日推荐