基于单链表的面试题——进阶篇

点击查看如何实现单链表以及单链表的一些基本操作函数
点击查看基于单链表经常见的面试题——基础篇

1.判断单链表是否带环?若带环,求环的长度?求环的入口点?

这里写图片描述
判断是否带环:

ListNode *IfRing(ListNode *list)//判断单链表是否带环,返回交点
{
    ListNode* slow = list;
    ListNode* fast = list;

    //是否带环
    while (fast&&fast->next)//注意边界问题
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)//如果相遇,则带环
        {
            return fast;
        }
    }
    return NULL;
}

求环的长度,只需要让快慢指针再遍历一遍环,再次相遇就可以求出长度了

int LengthRing(ListNode *list)//环的长度
{
    ListNode* fast = IfRing(list);
    if (fast!=NULL)
    {
        int count = 1;
        ListNode* slow = fast;
        while (fast&&fast->next)//注意边界问题
        {
            slow = slow->next;
            fast = fast->next->next;
            if (fast == slow)//如果再相遇,则能求出长度
            {
                break;
            }
            count++;
        }
        return count;
    }
    else
    {
        return 0;
    }
}

求环的入口点
这里写图片描述

ListNode *OepRing(ListNode *list)//环的入口点
{
    ListNode *fast = IfRing(list);
    if (fast != NULL)
    {
        ListNode *cur = list;
        while (fast != cur)
        {
            fast = fast->next;
            cur = cur->next;
        }
        return cur;
    }
    else
    {
        return NULL;
    }
}

在这里我也直接写了一个一次性求出的封装函数

void IfLengOepRing(ListNode *list)
//判断单链表是否带环?若带环,求环的长度?
//求环的入口点?
{
    assert(list);
    ListNode* slow = list;
    ListNode* fast = list;

    //是否带环
    while (fast&&fast->next)//注意边界问题
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)//如果相遇,则带环,求环的长度和入口点
        {
            printf("此链表带环\n");

            //求环的长度
            {
                int count = 1;
                while (fast&&fast->next)//注意边界问题
                {
                    slow = slow->next;
                    fast = fast->next->next;
                    if (fast == slow)//如果再次相遇,跳出循环,输出循环多少次,也就是环的长度
                    {
                        printf("环的长度为%d\n",count);
                        break;
                    }
                    count++;
                }
            }

            //环的入口点
            {
                ListNode *cur = list;
                while (fast != cur)
                {
                    fast = fast->next;
                    cur = cur->next;
                }
                printf("入口点为%d\n",cur->data);

            }

            break;
        }
    }
    if ((fast==NULL)||(fast->next==NULL))//如果为空了,表示不带环
    {
        printf("此链表不带环\n");
    }

}

2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)

这里写图片描述

ListNode *Intersect(ListNode *list, ListNode *plist)
//判断两个链表是否相交,若相交,求交点。(假设每个链表不带环)
{
    //找到第一个链表的尾结点,
    ListNode *cur = list;
    ListNode *tail = list;
    while (tail->next)
    {
        tail = tail->next;
    }

    //第一个链表的尾节点指向第二个链表的开始结点
    tail->next = plist;


    //判断是否相交(转换为是否带环问题)
    ListNode*ret = IfRing(cur);
    return ret;

}

3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

这里写图片描述

ListNode *IntersectRing(ListNode *list, ListNode *plist)
//判断两个链表是否相交,若相交,求交点。
//(假设链表可能带环)【升级版】
{
    ListNode* oep1 = OepRing(list);
    ListNode* oep2 = OepRing(plist);

    //两个链表都不带环(也就是上一题的解决方案)  
    if ((oep1 == NULL) && (oep2 == NULL))
    {
        return Intersect(list, plist);
    }

    //一个带环,一个不带环(不可能相交) 
    else if (((oep1 == NULL) && oep2) || ((oep2 == NULL) && oep1))
    {
        return NULL;
    }

    //两个都带环   
    else
    {
        //尾交(一个交点,一个入口点)
        //若两个链表的入口点一样则只有一个交点(交点也是入口点)
        //两链表各自环入口点已经求出,把list的环从入口点断开
        //可以转换成求不带环的相交链表求交点
        if (oep1 == oep2)
        {
            oep1->next = NULL;
            return Intersect(list, plist);//交点

        }

        else
        {
            //环交 
            //环交会有两个入口点,从一个入口点出发遍历环
            //遍历的过程中有结点等于另一个入口点,则表示环交,返回指向那个结点的指针(就是交点)
            //有两个交点,交点也是入口点。
            //否则,就是两个带环链表不相交


            //在这里返回的是第二个链表的入口点
            //也是第一个链表在第二个链表中的交点
            ListNode* cur = oep1->next;
            while (cur != oep1)
            {
                if (cur == oep2)
                {
                    return oep1;
                }
                cur = cur->next;
            }

            /*//在这里返回的是第一个链表的入口点
            //也是第二个链表在第一个链表中的交点

            ListNode* cur = oep2->next;
            while (cur != oep2)
            {
                if (cur == oep1)
                {
                    return oep2;
                }
                cur = cur->next;
            }*/
            return NULL;    //不相交  
        }
    }
}

4.复杂链表的复制。一个链表的每个节点,有一个指向next指针指向下一个节点,还有一个random指针指向这个链表中的一个随机节点或者NULL,现在要求实现复制这个链表,返回复制后的新链表。

//ps: 复杂链表的结构
struct ComplexNode
{
int _data ; // 数据
struct ComplexNode * _next; // 指向下一个节点的指针
struct ComplexNode * _random; // 指向随机节点(可以是链表中的任意节点 or 空)
};

复制复杂链表思路:
1)第一步,把新创建的每个结点链接到原先结点的后面
这里写图片描述

void NewBackPrime(ComplexNode *list)
//第一步,把新创建的每个结点链接到原先结点的后面
{
    ComplexNode *cur = list;
    while (cur)
    {
        //每次新创建一个结点,让它指向原先结点指向的结点
        //新创建结点的data和原先结点一样
        ComplexNode *head = Init(cur->_data);
        head->_next = cur->_next;

        //新创建结点的指向的随机结点置空
        head->_random = NULL;

        //原先结点指向新创建的结点,这样整个链表就连到了一块
        cur->_next = head;

        //cur依次后移
        cur = head->_next;

    }
}

2)第二步,复制随机结点
这里写图片描述

void ComplexNodeRandom(ComplexNode *list)
//第二步,复制随机结点
{
    ComplexNode *cur = list;
    while (cur)
    {
        //找到插入的新结点
        ComplexNode *head = cur->_next;

        //让新结点指向的随机结点 
        //去指向 
        //原先结点指向随机结点的后一个
        if (cur->_random)
        {
            head->_random = cur->_random->_next;
        }
        cur = head->_next;

    }
}

3)第三步,让新创建链表的结点链接起来,原先链表的结点链接起来

ComplexNode *RemoveNewCode(ComplexNode *list)
//第三步,让新创建链表的结点链接起来,原先链表的结点链接起来
{
    ComplexNode *cur = list;
    ComplexNode *head = NULL;
    ComplexNode *tmp = NULL;
    if (cur)
    {
        head = tmp = cur->_next;
        cur->_next = tmp->_next;
        cur = cur->_next;
    }
    while (cur)
    {
        //让新创建链表的结点链接起来
        tmp->_next = cur->_next;
        tmp = tmp->_next;

        //原先链表的结点链接起来
        cur->_next = tmp->_next;
        cur = cur->_next;
    }
    return head;

}

将这三步放到一块就是复杂链表的复制;

ComplexNode *ComplexList(ComplexNode *list)
//复杂链表的复制
{
    NewBackPrime(list);
    ComplexNodeRandom(list);
    return RemoveNewCode(list);
}

同样,提供全部测试代码:

singlelinkedlist.h头文件

#ifndef __SINGLELINKEDLIST_H__
#include<stdio.h>
#include<windows.h>
#include<assert.h>
typedef int DataType;

typedef struct ListNode
{
    DataType data;
    struct ListNode *next;

}ListNode;
typedef struct ComplexNode
{
    int _data; // 数据 
    struct ComplexNode *_next; // 指向下一个节点的指针 
    struct ComplexNode *_random; // 指向随机节点(可以是链表中的任意节点 or 空) 
}ComplexNode;


ListNode *InitList(DataType num);//初始化并赋值
void PushBack(ListNode **pplist, DataType num);//尾插
void PrintList(ListNode *plist);//输出
void PopBack(ListNode **pplist);//尾删
void PushFront(ListNode **pplist, DataType num);//头插
void PopFront(ListNode **pplist);//头删
ListNode *Find(ListNode *plist, DataType num);//查找
void Insert(ListNode** pplist, ListNode* pos, DataType x);//插入
void Erase(ListNode** pplist, ListNode* pos);//删除
void reverse(ListNode* pplist);//从尾到头打印链表
void DelHeadlessTail(ListNode* pos);//删除非尾结点
void InsertNotHeadNode(ListNode *pos, DataType num);//在一个节点前插入一个节点
void YueSeFu(ListNode *plist, DataType num);//约瑟夫环问题
void ReverseList(ListNode **pplist);//逆序单链表  
void SortList(ListNode *plist);//冒泡排序
ListNode *MergeList(ListNode *list, ListNode *plist);//(尾插法)合并有序链表并输出有序
ListNode *MidNode(ListNode *list);//查找单链表的中间节点,要求只能遍历一次链表 
ListNode *CountBackwards(ListNode *list, DataType num);//查找单链表的倒数第k个节点,要求只能遍历一次链表
ListNode *Ring(ListNode *list);//给链表带环
void IfLengOepRing(ListNode *list);//判断单链表是否带环?若带环,求环的长度?求环的入口点?
ListNode *IfRing(ListNode *list);//判断单链表是否带环,返回交点
int LengthRing(ListNode *list);//环的长度
ListNode *OepRing(ListNode *list);//环的入口点
ListNode *Intersect(ListNode *list, ListNode *plist);//判断两个链表是否相交,若相交,求交点。(假设每个链表不带环)
ListNode *IntersectRing(ListNode *list, ListNode *plist);//判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

ComplexNode *ComplexList(ComplexNode *list);//复杂链表的复制
ComplexNode *Init(DataType num);//定义一个新结构体链表结点
void NewBackPrime(ComplexNode *list);//第一步,把新创建的每个结点链接到原先结点的后面
void ComplexNodeRandom(ComplexNode *list);//第二步,复制随机结点
ComplexNode *RemoveNewCode(ComplexNode *list);//第三步,让新创建链表的结点链接起来,原先链表的结点链接起来
void PushBackComplex(ComplexNode **pplist, DataType num);//尾插,为了方便复制复杂链表使用
ComplexNode *FindComplex(ComplexNode *plist, DataType num);//查找
#endif//__SINGLELINKEDLIST_H__

singlelinkedlist.c实现部分

#include "singlelinkedlist.h"


ListNode *InitList(DataType num)//定义一个新的结点
{
    ListNode *node = (ListNode*)malloc(sizeof(ListNode));
    node->data = num;
    node->next = NULL;
    return node;
}


void PushBack(ListNode **pplist, DataType num)//尾插
{

    if (*pplist == NULL)//空链表
    {
        *pplist = InitList(num);//定义一个结点
    }
    else if ((*pplist)->next == NULL)//只有一个结点
    {
        (*pplist)->next = InitList(num);
    }
    else//正常情况(多个结点)
    {
        ListNode *tail = *pplist;
        while (tail->next)
        {
            tail = tail->next;//依次指向下一个结点,找到为空的尾结点
        }
        tail->next = InitList(num);//找到以后直接添加一个结点
    }
}


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




void PopBack(ListNode **pplist)//尾删
{
    if (*pplist == NULL)//空链表
    {
        return;
    }
    else if ((*pplist)->next == NULL)//只有一个结点,直接释放
    {
        free(*pplist);
        *pplist = NULL;
    }
    else
    {
        ListNode* tail = *pplist;
        ListNode* pos = tail;
        while (tail->next)//tail指向pos的后一个结点
        {
            pos = tail; 
            tail = tail->next;
        }
        free(tail);//释放最后一个结点就相当于删除了尾结点
        tail = NULL;
        pos->next = NULL;
    }
}


void PushFront(ListNode **pplist, DataType num)//头插
{
    if (*pplist == NULL)//空链表
    {
        *pplist = InitList(num);
    }
    else
    {
        ListNode *tmp = InitList(num);//开辟一个新的结点
        tmp->next = *pplist;//让它指向原先的开始结点
        *pplist = tmp;//pplist依然开始结点
    }
}


void PopFront(ListNode **pplist)//头删
{
    if (*pplist == NULL)//空链表
    {
        return;
    }
    else if ((*pplist)->next == NULL)//只有一个结点
    {
        *pplist = NULL;
    }
    else
    {
        ListNode *tmp = (*pplist)->next;//tmp指向原先头结点指向的下一个位置
        free(*pplist);
        *pplist = tmp;
    }

}


ListNode *Find(ListNode *plist, DataType num)//查找
{
    assert(plist);//断言其是否为空链表
    while (plist)
    {
        if (plist->data == num)
        {
            return plist;
        }
        plist = plist->next;
    }
    return NULL;
}


void Insert(ListNode** pplist, ListNode* pos, DataType num)//插入
{
    assert(*pplist&&pos);
    if (((*pplist)->next == NULL) || (pos == *pplist))
        //只有开始结点或者是要插入的正好在开始结点的前面
    {
        PushFront(pplist, num);
    }
    else
    {
        ListNode* tmp = NULL;
        ListNode* tail = *pplist;
        while (tail->next != pos)
        {
            tail = tail->next;
        }
        tmp = InitList(num);
        tail->next = tmp;
        tmp->next = pos;
    }
}


void Erase(ListNode** pplist, ListNode* pos)//删除
{
    assert(*pplist&&pos);
    if (((*pplist)->next == NULL) || (*pplist == pos))
    {
        PopFront(pplist);
    } 
    else
    {
        ListNode* tmp = *pplist;
        while (tmp->next != pos)
        {
            tmp = tmp->next;
        }
        tmp->next = pos->next;
        free(pos);
        pos = NULL;
    }
}


void reverse(ListNode* plist)
//要实现反过来输出链表,我们每访问到一个结点的时候
//先递归输出它后面的结点,再输出该结点自身
//问题:当链表非常长的时候,就会导致函数调用的层级很深
//从而有可能导致函数调用栈溢出。
{
    if (NULL == plist)
    {
        printf("NULL");
        return;
    }
    reverse(plist->next);
    printf("<-%d", plist->data);
}


void DelHeadlessTail(ListNode *pos)//删除无头链表的非尾结点
//由于链表的单向性,我们只能知道一个结点所指向的下一个结点
//我们可以把问题想象成是此结点与后一个结点交换
//只要把两个结点的数据域交换,把结点指向后一个结点所指向的结点
{
    assert(pos);
    ListNode *ppos = pos->next;
    pos->data = ppos->data;
    pos->next = ppos->next;
    free(ppos);
    ppos = NULL;
}


void InsertNotHeadNode(ListNode *pos,DataType num)
//4.在无头单链表的一个节点前插入一个节点
//实现原理
//A->pcur->B->C.....  
//A->pcur->new->B->C.....  
//A->new->pcur->B->C..... 
{
    assert(pos);
    ListNode *tmp = InitList(num);
    ListNode *ppos = pos;  //记住原来节点的位置
    tmp->next = pos->next;
    pos->next = tmp;
    tmp->data = pos->data;
    pos->data = num;
}


void YueSeFu(ListNode *plist, DataType num)//约瑟夫环问题,报数为num的人出局
{
    assert(plist);
    ListNode *cur = plist;
    ListNode *tmp = plist;

    if (plist->next == NULL)
    {
        return;
    }
    while (cur->next != NULL)
    {
        cur = cur->next;
    }
    cur->next = tmp;//环形链表
    cur = plist;
    while (cur->next != cur)//头不等于尾,也就是剩下1个人就终止循环
    {
        DataType n = num;
        while (--n)
        {
            tmp = cur;
            cur = cur->next;
        }
        tmp->next = cur->next;//删除cur也就是报数为num的人
        printf("出局的为%d\n", cur->data);
        free(cur);
        cur = tmp->next;//头往后走,也就是下一个人开始报数
    }
    printf("剩下的是%d\n",cur->data);
}


void ReverseList(ListNode **pplist) //逆序单链表  
{
    ListNode *cur = *pplist;//cur当前结点
    ListNode *prev = NULL;//前一个结点
    ListNode *pnext = NULL;//后一个结点
    if (NULL == *pplist || NULL == (*pplist)->next)
        return;
    while (cur)
    {
        pnext = cur->next;
        cur->next = prev;
        prev = cur;
        cur = pnext;

    }
    *pplist = prev;
}


void SortList(ListNode *plist)//冒泡排序
{
    if ((plist == NULL) || (plist->next == NULL))
    {
        return;
    }
    int exchange = 0;
    ListNode *tail = NULL;
    while (tail != plist->next)
    {
        ListNode *cur = plist;
        ListNode *next = plist->next;
        while (next != tail)
        {
            if (cur->data > next->data)
            {
                DataType num = cur->data;
                cur->data = next->data;
                next->data = num;
                exchange = 1;
            }
            cur = cur->next;
            next = next->next;
        }
        if (exchange == 0)//冒泡优化
        {
            break;
        }
        tail = cur;
    }
}


ListNode *MergeList(ListNode *list, ListNode *plist)//合并有序链表并输出有序
{//归并法(尾插法)
    if (list == NULL)//如果链表1为空,则直接返回链表2的头指针
    {
        return list;
    }
    else if (plist == NULL)//如果链表2为空,则直接返回链表1的头指针
    {
        return list;
    }
    else
    {
        //找出新链表的头结点
        ListNode *head = NULL;
        if (list->data < plist->data)
        {
            head = list;
            list = list->next;
        }
        else
        {
            head = plist;
            plist = plist->next;
        }

        //尾插
        ListNode *tail = head;
        while (list && plist)
        {
            if (list->data < plist->data)
            {
                tail->next = list;
                list = list->next;
            }
            else
            {
                tail->next = plist;
                plist = plist->next;
            }
            tail = tail->next;
        }
        if (list)//循环结束,一个链表为空,头指针直接指向非空链表的开始结点
        {
            tail->next = list;
        }
        else
        {
            tail->next = plist;
        }
        return head;
    }
}


ListNode *MidNode(ListNode *list)//查找单链表的中间节点,要求只能遍历一次链表 
{
    //链表个数为偶数时,输出中间两个结点的后一个,也就是slow
    //当面试官说把两个中间值都输出来,那就把Slow和slow,这里用大写区分
    //要输出中间值的第一个,那就更改循环条件为fast&&fast->next->next
    ListNode *slow = list;
    //ListNode *Slow = list;
    ListNode *fast = list;
    while (fast&&fast->next)//while (fast&&fast->next->next)
        //要注意边界问题
    {
        //Slow = slow;   //Slow比slow后一个位置
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}


ListNode *CountBackwards(ListNode *list, DataType num)
//查找单链表的倒数第k个节点,要求只能遍历一次链表
{
    ListNode *slow = list;
    ListNode *fast = list;
    while (--num)
    {
        fast = fast->next;
        if (fast == NULL)
        {
            return NULL;
        }
    }
    while (fast->next)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}


ListNode *Ring(ListNode *list)//给链表带环
{
    ListNode *cur = list;
    ListNode *tail = list;
    //找到尾结点
    while (tail->next)
    {
        tail = tail->next;
    }
    //找到中间节点
    ListNode*mid = MidNode(cur);

    //带环,返回头指针
    tail->next = mid;
    return list;
}


void IfLengOepRing(ListNode *list)
//判断单链表是否带环?若带环,求环的长度?
//求环的入口点?
{
    assert(list);
    ListNode* slow = list;
    ListNode* fast = list;

    //是否带环
    while (fast&&fast->next)//注意边界问题
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)//如果相遇,则带环,求环的长度和入口点
        {
            printf("此链表带环\n");

            //求环的长度
            {
                int count = 1;
                while (fast&&fast->next)//注意边界问题
                {
                    slow = slow->next;
                    fast = fast->next->next;
                    if (fast == slow)//如果再次相遇,跳出循环,输出循环多少次,也就是环的长度
                    {
                        printf("环的长度为%d\n",count);
                        break;
                    }
                    count++;
                }
            }

            //环的入口点
            {
                ListNode *cur = list;
                while (fast != cur)
                {
                    fast = fast->next;
                    cur = cur->next;
                }
                printf("入口点为%d\n",cur->data);

            }

            break;
        }
    }
    if ((fast==NULL)||(fast->next==NULL))//如果为空了,表示不带环
    {
        printf("此链表不带环\n");
    }

}

ListNode *IfRing(ListNode *list)//判断单链表是否带环,返回相遇的那个点
{
    ListNode* slow = list;
    ListNode* fast = list;

    //是否带环
    while (fast&&fast->next)//注意边界问题
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)//如果相遇,则带环
        {
            return fast;
        }
    }
    return NULL;
}

int LengthRing(ListNode *list)//环的长度
{
    ListNode* fast = IfRing(list);
    if (fast!=NULL)
    {
        int count = 1;
        ListNode* slow = fast;
        while (fast&&fast->next)//注意边界问题
        {
            slow = slow->next;
            fast = fast->next->next;
            if (fast == slow)//如果再相遇,则能求出长度
            {
                break;
            }
            count++;
        }
        return count;
    }
    else
    {
        return 0;
    }
}

ListNode *OepRing(ListNode *list)//环的入口点
{
    ListNode *fast = IfRing(list);
    if (fast != NULL)
    {
        ListNode *cur = list;
        while (fast != cur)
        {
            fast = fast->next;
            cur = cur->next;
        }
        return cur;
    }
    else
    {
        return NULL;
    }
}


ListNode *Intersect(ListNode *list, ListNode *plist)
//判断两个链表是否相交,若相交,求交点。(假设每个链表不带环)
{
    //找到第一个链表的尾结点,
    ListNode *cur = list;
    ListNode *tail = list;
    while (tail->next)
    {
        tail = tail->next;
    }

    //第一个链表的尾节点指向第二个链表的开始结点
    tail->next = plist;


    //判断是否相交(转换为是否带环问题)
    return  OepRing(cur);

}


ListNode *IntersectRing(ListNode *list, ListNode *plist)
//判断两个链表是否相交,若相交,求交点。
//(假设链表可能带环)【升级版】
{
    ListNode* oep1 = OepRing(list);
    ListNode* oep2 = OepRing(plist);

    //两个链表都不带环(也就是上一题的解决方案)  
    if ((oep1 == NULL) && (oep2 == NULL))
    {
        return Intersect(list, plist);
    }

    //一个带环,一个不带环(不可能相交) 
    else if (((oep1 == NULL) && oep2) || ((oep2 == NULL) && oep1))
    {
        return NULL;
    }

    //两个都带环   
    else
    {
        //尾交(一个交点,一个入口点)
        //两个链表的入口点一样,只有一个交点
        //两链表各自环入口点已经求出,把list的环从入口点断开
        //可以转换成求不带环的相交链表求交点
        if (oep1 == oep2)
        {
            oep1->next = NULL;
            return Intersect(list, plist);//交点

        }

        else
        {
            //环交 
            //环交会有两个入口点,从一个入口点出发遍历环
            //遍历的过程中有结点等于另一个入口点,则表示环交,返回指向那个结点的指针(就是交点)
            //有两个交点,交点也是入口点。
            //否则,就是两个带环链表不相交


            //在这里返回的是第二个链表的入口点
            //也是第一个链表在第二个链表中的交点
            ListNode* cur = oep1->next;
            while (cur != oep1)
            {
                if (cur == oep2)
                {
                    return oep1;
                }
                cur = cur->next;
            }

            /*//在这里返回的是第一个链表的入口点
            //也是第二个链表在第一个链表中的交点

            ListNode* cur = oep2->next;
            while (cur != oep2)
            {
                if (cur == oep1)
                {
                    return oep2;
                }
                cur = cur->next;
            }*/
            return NULL;    //不相交  
        }
    }
}

ComplexNode *Init(DataType num)//定义一个新结构体链表结点
{
    ComplexNode *node = (ComplexNode*)malloc(sizeof(ComplexNode));
    node->_data = num;
    node->_next = NULL;
    node->_random = NULL;
    return node;
}



void NewBackPrime(ComplexNode *list)
//第一步,把新创建的每个结点链接到原先结点的后面
{
    ComplexNode *cur = list;
    while (cur)
    {
        //每次新创建一个结点,让它指向原先结点指向的结点
        //新创建结点的data和原先结点一样
        ComplexNode *head = Init(cur->_data);
        head->_next = cur->_next;

        //新创建结点的指向的随机结点置空
        head->_random = NULL;

        //原先结点指向新创建的结点,这样整个链表就连到了一块
        cur->_next = head;

        //cur依次后移
        cur = head->_next;

    }
}

void ComplexNodeRandom(ComplexNode *list)
//第二步,复制随机结点
{
    ComplexNode *cur = list;
    while (cur)
    {
        //找到插入的新结点
        ComplexNode *head = cur->_next;

        //让新结点指向的随机结点 
        //去指向 
        //原先结点指向随机结点的后一个
        if (cur->_random)
        {
            head->_random = cur->_random->_next;
        }
        cur = head->_next;

    }
}


ComplexNode *RemoveNewCode(ComplexNode *list)
//第三步,让新创建链表的结点链接起来,原先链表的结点链接起来
{
    ComplexNode *cur = list;
    ComplexNode *head = NULL;
    ComplexNode *tmp = NULL;
    if (cur)
    {
        head = tmp = cur->_next;
        cur->_next = tmp->_next;
        cur = cur->_next;
    }
    while (cur)
    {
        //让新创建链表的结点链接起来
        tmp->_next = cur->_next;
        tmp = tmp->_next;

        //原先链表的结点链接起来
        cur->_next = tmp->_next;
        cur = cur->_next;
    }
    return head;

}

ComplexNode *ComplexList(ComplexNode *list)
//复杂链表的复制
{
    NewBackPrime(list);
    ComplexNodeRandom(list);
    return RemoveNewCode(list);
}


void PushBackComplex(ComplexNode **pplist, DataType num)//尾插,为了方便复制复杂链表使用
{
    if (*pplist == NULL)//空链表
    {
        *pplist = Init(num);//定义一个结点
    }
    else if ((*pplist)->_next == NULL)//只有一个结点
    {
        (*pplist)->_next = Init(num);
    }
    else//正常情况(多个结点)
    {
        ComplexNode *tail = *pplist;
        while (tail->_next)
        {
            tail = tail->_next;//依次指向下一个结点,找到为空的尾结点
        }
        tail->_next = Init(num);//找到以后直接添加一个结点
    }
}


ComplexNode *FindComplex(ComplexNode *plist, DataType num)//查找
{
    assert(plist);//断言其是否为空链表
    while (plist)
    {
        if (plist->_data == num)
        {
            return plist;
        }
        plist = plist->_next;
    }
    return NULL;
}

test.c测试部分

#include "singlelinkedlist.h"



void test()
{
    ListNode *list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PrintList(list);
    PopBack(&list);
    PrintList(list);
    PopBack(&list);
    PrintList(list);
    PopBack(&list);
    PrintList(list);
    PopBack(&list);
    PrintList(list);
}



void test1()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PrintList(list);
    PopFront(&list);
    PrintList(list);
    PopFront(&list);
    PrintList(list);
    PopFront(&list);
    PrintList(list);
    PopFront(&list);
    PrintList(list);
    PopFront(&list);
    PrintList(list);
}


void test2()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PushFront(&list, 6);
    PrintList(list);
    ListNode *ret = Find(list, 2);
    //测试使用
    /*if (ret != NULL)
    {
        printf("%p\n", ret);
    }
    else
    {
        printf("没有这个值!\n");
    }*/
    Insert(&list, ret, 3);
    PrintList(list);
    Erase(&list, ret);
    PrintList(list);
}


void test3()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PrintList(list);
    reverse(list);//从尾到头打印链表
    printf("\n");
}


void test4()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PrintList(list);
    ListNode *ret = Find(list, 2);
    DelHeadlessTail(ret);//删除非尾结点
    PrintList(list);

}


void test5()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PushFront(&list, 6);
    PrintList(list);
    ListNode *ret = Find(list, 2);
    InsertNotHeadNode(ret, 3);//在一个节点前插入一个节点
    PrintList(list);
    YueSeFu(list, 2);//约瑟夫环问题

}



void test6()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PrintList(list);
    ReverseList(&list);//单链表的逆置
    PrintList(list);

}


void test7()
{
    ListNode *list = NULL;
    PushFront(&list, 3);
    PushFront(&list, 2);
    PushFront(&list, 5);
    PushFront(&list, 4);
    PushFront(&list, 8);
    PrintList(list);
    SortList(list);//冒泡排序
    PrintList(list);

}


void test8()
{
    ListNode *tmp = NULL;
    PushFront(&tmp, 5);
    PushFront(&tmp, 3);
    PushFront(&tmp, 1);
    PrintList(tmp);
    ListNode *num = NULL;
    PushFront(&num, 6);
    PushFront(&num, 4);
    PushFront(&num, 2);
    PrintList(num);
    //ListNode *ret = MergeList(tmp, num);//尾插法
    //PrintList(ret);

}


void test9()
{
    ListNode *list = NULL;
    //PushFront(&list, 3);
    //PushFront(&list, 2);
    //PushFront(&list, 5);
    //PushFront(&list, 4);
    //PushFront(&list, 8);
    //ListNode *ret = MidNode(list);//查找单链表的中间节点,要求只能遍历一次链表 
    //printf("%d\n",ret->data);//链表个数如果是奇数个,输出中间那个
    PushFront(&list, 3);
    PushFront(&list, 2);
    PushFront(&list, 4);
    PushFront(&list, 8);
    ListNode *Ret = MidNode(list);//查找单链表的中间节点,要求只能遍历一次链表 
    printf("%d\n", Ret->data);//链表个数如果是偶数个,输出中间两个结点的后一个

}



void test10()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);
    PushFront(&list, 5);
    PrintList(list);
    ListNode *ret = CountBackwards(list, 2);
    printf("%d\n",ret->data);

}



void test11()
{
    ListNode *list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);
    PushFront(&list, 7);
    PushFront(&list, 8);
    PushFront(&list, 9);
    PushFront(&list, 10);
    PushFront(&list, 11);
    PrintList(list);
    ListNode *ret = Ring(list);//给链表带环

    //IfLengOepRing(ret);//判断单链表是否带环?若带环,求环的长度?求环的入口点

    /*ListNode* Ret = IfRing(ret);//判断单链表是否带环
    if (Ret)
    {
        printf("该链表带环\n");
    }
    else
    {
        printf("该链表不带环\n");

    }*/

    //printf("环的长度为:%d\n", LengthRing(ret));//环的长度

    ListNode *Ret = OepRing(ret);//环的入口点
    if (Ret)
    {
        printf("环的入口点为:%d\n",Ret->data);
    }
    else
    {
        printf("该链表没有环\n");

    }

}

void test12()
{
    ListNode *list = NULL;
    PushFront(&list, 8);
    PushFront(&list, 7);
    PushFront(&list, 6);
    PushFront(&list, 5);
    PushFront(&list, 4);
    PushFront(&list, 3);
    PushFront(&list, 2);
    PushFront(&list, 1);
    PrintList(list);
    ListNode *plist = NULL;

    PushFront(&plist, 5);
    PushFront(&plist, 4);
    PushFront(&plist, 3);
    PushFront(&plist, 2);
    PrintList(plist);
    //Find(plist, 5)->next = Find(list, 6);//让两个链表相交
    ListNode *ret = Intersect(list, plist);//判断两个链表是否相交,若相交,求交点。(假设链表不带环)
    if (ret)
    {
        printf("两个链表相交,交点为:%d\n", ret->data);
    }
    else
    {
        printf("两个链表不相交\n");

    }


}


void test13()
{

    ListNode *list = NULL;
    PushFront(&list, 4);
    PushFront(&list, 3);
    PushFront(&list, 2);
    PushFront(&list, 1);
    ListNode *ret = Ring(list);//给链表带环

    ListNode *plist = NULL;
    PushFront(&plist, 4);
    PushFront(&plist, 3);
    PushFront(&plist, 2);
    PushFront(&plist, 1);
    ListNode *Ret = Ring(plist);//给链表带环
    //Find(plist, 3)->next = Find(list, 3);//让两个链表尾交
    //Find(plist, 4)->next = Find(list, 3);//让两个链表环交

    ListNode *oep = IntersectRing(ret, Ret);//判断两个链表是否相交,若相交,求交点。(假设链表可能带环)
    if (oep != NULL)
    {
        printf("交点为:%d\n",oep->data);
    }
    else
    {
        printf("无交点\n");
    }

}

void test14()
{
    ComplexNode *list = NULL;
    PushBackComplex(&list, 4);
    PushBackComplex(&list, 3);
    PushBackComplex(&list, 2);
    PushBackComplex(&list, 1);
    FindComplex(list, 1)->_random = FindComplex(list, 3);
    FindComplex(list, 2)->_random = FindComplex(list, 4);
    FindComplex(list, 3)->_random = NULL;
    FindComplex(list, 4)->_random = NULL;
    ComplexNode *plist = ComplexList(list);
}


int main()
{
    //test();
    //test1();
    //test2();
    //test3();
    //test4();
    //test5();
    //test6();
    //test7();
    //test8();
    //test9();
    //test10();
    //test11();
    //test12();
    //test13();
    test14();
    system("pause");
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值