单链表的基本操作和链表的面试题

List.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<malloc.h>
typedef int DataType;
typedef struct Node
{
    DataType data;//数据
    struct Node* next;//指向下一个节点的指针(结构体指针)

}Node;
//修改链表的传的的**
Node* BuyNode(DataType x);//创建一个节点
void PushBack(Node** ppHead, DataType x);//尾插
void PopBack(Node** ppHead);//尾删
void PushFront(Node** ppHead,DataType x);//头插
void PopFront(Node** ppHead);//头删
void Insert(Node** ppHead,Node* pos, DataType x);//任意位置的前面插入(在pos的前面插入)
void Erase(Node** ppHead, Node* pos);//删除任意位置的节点
void PrintList(Node* pHead);//打印
Node* Find(Node*pHead, DataType x);//在链表中找数据
//******************面试题**************************
void PrintTailToHead(Node* head);//从尾到头打印节点
void EraseNoTail(Node* pos);//删除一个无头单链表的非尾节点(不能遍历链表)
void InsertFront(Node* pos, DataType x);//在无头单链表的一个节点前插入一个节点(不能遍历节点)
Node* Josephus(Node* hus, int k);//约瑟夫环
void ReverseList(Node** ppNode);//逆置/反转单链表
void SortList(Node *pHead);//排序单链表
Node* MergeList(Node* list1, Node* list2);//合并两个有序链表,合并后依然有序
Node*  FindMidNode(Node* pHead);//查找单链表的中间节点,要求只能遍历一次链表
Node* FindTailKNode(Node* pHead, size_t k);//查找单链表的倒数第K个节点,要求只能遍历一次链表
Node* IsCycle(Node* pHead);//判断单链表是否带环
int GetCircleLen(Node* pMeetNode);//求环的长度
Node* GetEntry(Node* pHead, Node* meet);//求环的入口点。
int IsSListCrossWithCircle(Node *pHead1, Node* pHead2);//两个链表是否相交(第一种带环,第二种不带环)
int IsSListCross(Node *pHead1, Node* pHead2);//两个链表相交的交点。

List.c

#include"List.h"
Node* BuyNode(DataType x)//创建一个节点
{
    Node* node = (Node*)malloc(sizeof(Node));
    node->data = x;
    node->data = NULL;
    return node;
}
void PushBack(Node** ppHead, DataType x)
//ppHead并不是第一个节点的指针而是指向第一个节点指针的地址.
//*ppHead也就是指向第一个节点的指针.
//需要改变指向的内容时用二级指针
{
    if (*ppHead == NULL)
    {
        *ppHead = BuyNode(x);
    }
    else
    {
        Node* tail = *ppHead;
        while (tail->next!= NULL)
        { 
            tail = tail->next;
        }
        tail->next = BuyNode(x);
    }
}
void PopBack(Node** ppHead)
//删除分三种情况:第一种情况是这个链表本来就是空
//第二种情况是这个链表有一个节点
//第三种情况就是有两个或者两个以上的节点这时候的操作就是必须把删除之前的一个保存下,然后把尾free再把前一个的next指向NILL。
{
    if (*ppHead == NULL)
    {
        return;
    }
    else if ((*ppHead)->next = NULL)
    {
        free(*ppHead);
        *ppHead = NULL;
    } 
    else
    {
        Node* cur = *ppHead;
        Node * prev = NULL;
        while (cur->next)
        {
            prev = cur;
            cur = cur->next;
        }
        prev->next = NULL;
        free(cur);
    }

}
void PushFront(Node** ppHead, DataType x)//头插
{

        Node* temp = BuyNode(x);
        temp->next = *ppHead;
        *ppHead = temp;

}
void PopFront(Node** ppHead)//头删
{
    if (*ppHead == NULL)//链表为空
    {
        return;
    }
    else if ((*ppHead)->next == NULL)//有一个节点
    {
        free(*ppHead);
        *ppHead = NULL;
    }
    else
    {
        Node* next = (*ppHead)->next; //保存下一个节点
        free(*ppHead);//删除头结点
        *ppHead = next;//让头指向新保存的节点
    }
}

void Insert(Node** ppHead, Node* pos, DataType x)//在pos前面插入一个节点
{
    assert(pos);
    if (pos == *ppHead)//当插入的这个位置为1时。
    {
        PushFront(ppHead,x);
    }
    else
    {
        Node* tmp = BuyNode(x);
        Node* prev = *ppHead;
        while (prev->next != pos)
        {
            prev = prev->next; 
        }
        prev->next = tmp;
        tmp->next = pos;
    }


}
void Erase(Node** ppHead, Node* pos)
{
    assert(pos);
    if (pos == *ppHead)//头
    {
        PopFront(ppHead);
    }
    else if (pos->next==NULL)//尾
    {
        PopBack(ppHead);
    }
    else//找pos的前一个,再找它的下一个
    {
        Node* prev = *ppHead;
        Node* next = pos->next;
        while (prev->next != pos)
        {
            prev = prev->next;
        }
        prev->next = next;
        free(pos);
    }
}
Node* Find(Node*pHead, DataType x)//在链表中找数据
{
    Node*cur = pHead;
    while (cur)
    {
        if (cur->data == x)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}
void PrintList(Node* pHead)//pHead指向第一个节点的指针
{
    Node* cur = pHead;
    while (cur)
    {
        printf("%d ", cur->data);
            cur = cur->next;
    }
    printf("\n");
}

void TestList1()
{
    Node* list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);

    PrintList(list);

    PopBack(&list);
    PopBack(&list);
    PopBack(&list);
    PopBack(&list);
    PopBack(&list);

    PrintList(list);
}
void TestList2()
{
    Node*pos;
    Node* list = NULL;
    PushFront(&list, 1);
    PushFront(&list, 2);
    PushFront(&list, 3);
    PushFront(&list, 4);

    PrintList(list);

    //PopFront(&list);  
    //PopFront(&list);
    //PopFront(&list);
    //PopFront(&list);

    //PrintList(list);

    pos = list;//指向开头
    pos = pos->next;//往后走了一步
    Insert(&list, pos, 30);
    PrintList(list); 

    pos = list;//头插 
    Insert(&list, pos, 30);
    PrintList(list);

    pos = Find(list, 30);
    if (pos)
        Erase(&list, pos);
    PrintList(list);


}

void PrintTailToHead(Node* head)//从尾到头打印节点
{
    if (head == NULL)
        return;
    PrintTailToHead(head->next);
    printf("%d ", head->data);
}
void Test()
{
    Node* list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    PrintTailToHead(list);
}

void EraseNoTail(Node* pos)//删除一个无头单链表的非尾节点(不能遍历链表)
{
    Node* next;
    assert(pos&&pos->next);
    next = pos->next;
    pos->data = next->data;
    pos->next = next->next;
    free(next);

}
void InsertFront(Node* pos, DataType x)//在无头单链表的一个节点前插入一个节点(不能遍历节点)
{
    Node* next, *tmp;
    assert(pos);
    next = pos->next;
    tmp = BuyNode(pos->data);
    pos->data = x;
    pos->next = tmp;
    tmp->next = next;
}
Node* Josephus(Node* hus, int k)//约瑟夫环
{
    Node* m, *next;
    assert(hus);
    m = hus;
    while (m->next != m)//只剩一个
    {
        int count = k;
        while (--count)
        {
            m = m->next;
        }
        next = m->next;
        m->data = next->data;
        m->next = next->next;
        free(next);
    }
    return m;

}
void ReverseList(Node** ppNode)//逆置/反转单链表
{
    Node* n0, *n1, *n2;//定义三个变量
    if (*ppNode == NULL)
    {
        return;
    }
    n0 = NULL;
    n1 = *ppNode;
    n2 = (*ppNode)->next;
    while (n1)
    {
        n1->next = n0;
        n0 = n1;
        n1 = n2;
        if (n2)
            n2 = n2->next;
    }
    *ppNode = n0;
    /*另外一种方法
    Node* cur = *ppNode;
    Node* newHead = NULL;
    while (cur)
    {
        //记录下一个
        Node* next = cur->next;
        //头插
        cur->next = newHead;
        newHead = cur;
        cur = next;
    }
    *ppNode = newHead;
    */

}
void SortList(Node *pHead)//排序单链表
{
    Node* tail = NULL;
    if (pHead == NULL || pHead->next == NULL)//单链表为空或者只有一个节点。
    {
        return;
    }
    while (tail != pHead)
    {
        int flag = 0;
        Node* cur = pHead, *next = cur->next;
        while (next != tail)
        {
            if (cur->data > next->data)
            {
                DataType tmp;
                flag = 1;
                tmp = cur->data;
                cur->data = next->data;
                next->data = tmp;
            }
            cur = cur->next;
            next = next->next;
        }
        if (flag == 0)
        {
            break;
        }
        tail = cur;
    }

}
void TestY()
{
    Node* tail;
    Node* list = NULL;
    PushBack(&list, 5);
    PushBack(&list, 2);
    PushBack(&list, 4);
    PushBack(&list, 3);
    PushBack(&list, 9);
    PrintList(list);

    SortList(list);
    PrintList(list);

}
Node* MergeList(Node* list1, Node* list2)//合并两个有序链表,合并后依然有序
{
    Node* list,*tail;
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;
    if (list1->data < list2->data)
    {
        list = list1;
        list1 = list1->next;
    }
    else
    {
        list = list2;
        list2 = list2->next;
    }
    tail = list;//开始尾插 
    while (list1 && list2)//两个链表有一个为空就停止
    {
        if (list1->data < list2->data)
        {
            tail->next = list1;
            list1 = list1->next;
        }
        else
        {
            tail->next = list2;
            list2 = list2->next;
        }
        tail = tail->next;
    }
    if (list)
    {
        tail->next = list1;

    }
    if (list2)
    {
        tail->next = list2;
    }
    return list;
}
void TestY1()
{
    Node* list = NULL;
    Node* list1 = NULL,*list2 = NULL;
    PushBack(&list1, 1);
    PushBack(&list1, 2);
    PushBack(&list1, 4);
    PushBack(&list1, 6);
    PushBack(&list1, 9);
    PrintList(list1);

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

    list = MergeList(list1, list2);
    PrintList(list);

}
Node*  FindMidNode(Node* pHead)//查找单链表的中间节点,要求只能遍历一次链表
{
    Node* slow = pHead, *fast = pHead;//定义两个指针
    while (fast && fast->next)
    //如果偶数个时候要找前一个时候将变为while(fast && fast->next&&fast->next->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}
void TestY2()//奇数时候
{
    Node* tail;
    Node* list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    //PushBack(&list, 5);偶数时候返回的是第二个
    PrintList(list);
    SortList(list);
    printf("mid:%d\n", FindMidNode(list)->data);

}
Node* FindTailKNode(Node* pHead, size_t k)//查找单链表的倒数第K个节点,要求只能遍历一次链表
{
    Node* slow = pHead, *fast = pHead;
    //先让fast走K步
    while (--k)//走了k-1步
    {
        if (fast == NULL)
        {
            return NULL;
        }
        fast = fast->next;
    }
    while (fast->next)//让慢的和快的一起走
    {
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}
void TestY3()//奇数时候
{
    Node* tail;
    Node* list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    //PushBack(&list, 5);偶数时候返回的是第二个
    PrintList(list);
    SortList(list);
    printf("tail k:%d\n", FindTailKNode(list,3)->data);
}
//怎么判断单链表带环呢?定义两个指针 一个快指针一个慢指针。快指针一次走两步慢指针一次走一步。
//进去环之后他们之间的距离每次他们都缩小
//如果快慢指针相遇则带环了。

Node* IsCycle(Node* pHead)//判断单链表是否带环
{
    Node* slow, *fast;
    slow = fast = pHead;
    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow)
        {
            return fast;
        }
    }
    return NULL;
}
int GetCircleLen(Node* pMeetNode)//求环的长度
{
    int count = 1;
    Node* pCur = pMeetNode;
    if (NULL == pMeetNode)
        return 0;
    while (pCur->next!=pMeetNode)
    {
        count++;
        pCur = pCur->next;
    }
    return count;
}
Node* GetEntry(Node* pHead, Node* meet)//求环的入口点。
{
    Node* pH = pHead;
    Node* pM = meet;
    while (pH != pM)
    {
        pH = pH->next;
        pM = pM->next;  
    }
    return pM;
}

void TestCycle()
{
    Node* pos,*tail,*meet;
    Node* list = NULL;
    PushBack(&list, 1);
    PushBack(&list, 2);
    PushBack(&list, 3);
    PushBack(&list, 4);
    PushBack(&list, 5);
    PushBack(&list, 6);
    PushBack(&list, 7);
    PushBack(&list, 8);


    //构成一个环
    pos = Find(list, 5);
    tail = Find(list, 8);
    tail->next = pos;

    meet = IsCycle(list);//找到相遇点
    printf("entry:%d\n", GetEntry(list, meet)->data);

}
//链表的相交问题:(都不带环或者都带环)
//尾相同就相交了,相交的就为叫点。
int IsSListCrossWithCircle(Node *pHead1, Node* pHead2)//两个链表是否相交(第一种带环,第二种不带环)
{
    //判断两个链表是否带环
    Node* pMeetNode1 = IsCycle(pHead1);
    Node* pMeetNode2 = IsCycle(pHead2);
    //两个链表都不带环
    if (NULL == pMeetNode1 && NULL == pMeetNode2)
    {
        Node* pTail1 = pHead1;
        Node* pTail2 = pHead2;
        while (pTail1->next)
            pTail1 = pTail1->next;
        while (pTail2->next)
            pTail2 = pTail2->next;
        if (pTail1 == pTail2)
            return 1;
    }
    //两个链表都带环
    else if (pMeetNode1&&pMeetNode2)
    {
        Node* pCur = pMeetNode1;
        while (pCur->next != pMeetNode1)
        {
            if (pCur == pMeetNode2)
                return 2;
            pCur = pCur->next;
        }
        if (pCur == pMeetNode2)
            return 2;
    }
    return 0;
}

int IsSListCross(Node *pHead1, Node* pHead2)//两个链表相交的交点。
{
    Node* pTail1 = pHead1, *pTail2 = pHead2;
    if (NULL == pHead1 || NULL == pHead2)
        return 0;

    while (pTail1->next)
        pTail1 = pTail1->next;
    while (pTail2->next)
        pTail2 = pTail2->next;

    return pTail1 = pTail2;
}



//复杂链表的复制
typedef struct CSListNode
{
    struct CSListNode* _pNext;
    struct CSListNode* _pRandom;
    DataType _data;
}CSListNode, *PCSListNode;

PCSListNode BuyComplexSListNode(DataType data)
{
    PCSListNode pNewNode = (PCSListNode)malloc(sizeof(CSListNode));
    if (NULL == pNewNode)
        assert(0);
    pNewNode->_data = data;
    pNewNode->_pNext = NULL;
    pNewNode->_pRandom = NULL;
    return pNewNode;
}
PCSListNode CopyComplexSList(PCSListNode pHead)
{
    //1、在原链表每个节点后插入值相同的新节点
    PCSListNode pCur = pHead;
    PCSListNode pNewNode;
    PCSListNode pNewHead = NULL;
    if (NULL == pHead)
        return NULL;
    while (pCur)
    {
        pNewNode = BuyComplexSListNode(pCur->_data);

        pNewNode->_pNext = pCur->_pNext;
        pCur->_pNext = pNewNode;
        pCur = pNewNode->_pNext;
    }
    //2、给新节点的随机指针域赋值
    pCur = pHead;
    while (pCur)
    {
        pNewNode = pCur->_pNext;
        if (pCur->_pRandom)
        pNewNode->_pRandom = pCur->_pRandom->_pNext;
        pCur = pNewNode->_pNext;
    }
    //3、将新插入的节点从原链表中拆下来。
    pNewHead = pHead->_pNext;
    pCur = pHead;
    while (pCur->_pNext)
    {
        pNewNode = pCur->_pNext;
        pCur->_pNext = pNewNode->_pNext;
        pCur = pNewNode;
    }
    return pNewHead;
}

void TestComplexSList()
{
    CSListNode node1, node2, node3, node4;
    PCSListNode pHead;
    node1._data = 1;
    node1._pNext = &node2;
    node1._pRandom = &node3;

    node2._data = 2;
    node2._pNext = &node3;
    node2._pRandom = &node1;

    node3._data = 3;
    node3._pNext = &node4;
    node3._pRandom = &node3;

    node4._data = 4;
    node4._pNext = NULL;
    node4._pRandom =NULL;


    pHead = CopyComplexSList(&node1);
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"List.h"
int main()
{
    //Tset();
    //TestList1();
    //TestList2();
    //TestY();
    //TestY1();
    //TestY2();
    //TestY3();
    //TestCycle()
    TestComplexSList();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值