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

原创 2018年04月16日 21:46:23

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;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41112517/article/details/79967182

单链表基本操作java实现

单链表基本操作 - java实现 1.单链表学习了好久,今天终于有时间写一下了,带头结点的单链表上的基本操作,Java实现。 (1) 先来个接口 public interface IList { ...
  • ping1632743560
  • ping1632743560
  • 2016-09-26 20:04:42
  • 394

单链表的基本操作c语言实现

#include #define false 0 #define ok 1//定义节点的结构 typedef struct node{ int data; struct node *n...
  • gongdileidechouzhu
  • gongdileidechouzhu
  • 2017-02-25 16:14:53
  • 1778

c++学习笔记—单链表基本操作的实现

用c++语言实现的单链表基本操作,包括单链表的创建(包括头插法和尾插法建表)、结点的查找、删除、排序、打印输出、逆置、链表销毁等基本操作。 IDE:vs2013 具体实现代码如下: #includ...
  • xujian_2014
  • xujian_2014
  • 2015-01-14 21:13:09
  • 1390

c++ 单链表基本操作

#include #include #include #include #include /*c++实现简单的单链表操作*/ using namespace std; typedef str...
  • cfan0801
  • cfan0801
  • 2012-03-13 21:01:44
  • 25054

第一篇博客—c语言单链表的基本操作

欢迎使用Markdown编辑器写博客本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦: Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和...
  • sakurakider
  • sakurakider
  • 2017-05-21 19:42:38
  • 669

单链表的基本操作-----图形解析

首先我们需要思考的是为什么需要单链表呢? 单链表和顺序表相比较,又有什么优点呢? 在顺序表中,当我们需要头插,或者在顺序表的中间位置插入元素时,就必须将后面的元素一一后移,再将需要插入的元...
  • qq_34992845
  • qq_34992845
  • 2016-12-31 01:12:28
  • 4437

数据结构实验报告单链表的基本操作

错误1 public void add(int idx,AnyType x){ Node newNode=new Node(x); if(headNode==null||idx==0){ newNod...
  • moonlululu
  • moonlululu
  • 2016-02-15 16:57:50
  • 1874

数据结构—单链表的基本操作(源代码)

#include &amp;lt;stdio.h&amp;gt; #include &amp;lt;stdlib.h&amp;gt; typedef int Elemtype; typedef s...
  • weixin_40908734
  • weixin_40908734
  • 2018-01-29 11:43:00
  • 74

单链表基本操作详解

#  单链表基本操作 文中提到的内容的链接一并列在这里: 顺序表:http://blog.csdn.net/bitboss/article/details/51559175 冒泡排序:...
  • bitboss
  • bitboss
  • 2016-06-04 22:12:46
  • 3170

【数据结构】 链表的19种基本操作(完整版)

基于这篇文章: http://www.cnblogs.com/lifuqing/archive/2011/08/20/List.html 作者最后只给出了前面12中操作的代码,这里我帮他补全 链表...
  • fanxingzju
  • fanxingzju
  • 2014-04-03 17:11:21
  • 1627
收藏助手
不良信息举报
您举报文章:单链表的基本操作和链表的面试题
举报原因:
原因补充:

(最多只允许输入30个字)