数据结构中单链表的那些事

在面试中面试数据结构中关于链表的基本操作,从未到头打印单链表、逆置\翻转单链表、合并两个有序链表,合并后链表依然有序、查找单链表的中间结点,只能遍历一次单链表、删除链表的倒数第K个结点,要求只能遍历一次单链表等链表的操作,都是面试中常考题,所以这些是必须会的,实现如下

head.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int DataType;

typedef struct ListNode
{
    struct ListNode* _pNext;
    DataType data;
}*PNode;



void PrintSListFromTail2Head(PNode pHead);                           // 逆序打印单链表 

void DeleteListNotTailNode(PNode pos);                               // 删除链表的非尾结点,要求:不能遍历链表 


void InesrtPosFront(PNode pos, DataType data);                      // 在链表pos位置前插入值到data的结点 


PNode FindMiddleNode(PNode pHead);                                  // 查找链表的中间结点,要求只能遍历一次链表 


PNode FindLastKNode(PNode pHead, int K);                            // 查找链表的倒数第K个结点,要求只能遍历一次链表


PNode DeleteLastKNode(PNode pHead, int K);                          // 删除链表的倒数第K个结点,要求只能遍历一次链表 


void JosephCircle(PNode* pHead, const int M);                       // 用单链表实现约瑟夫环 


void ReverseSList(PNode* pHead);                                    // 链表的逆置--三个指针 


PNode ReverseSListOP(PNode pHead);                                  // 链表的逆置--头插法 


void BubbleSort(PNode pHead);                                        // 用冒泡排序思想对单链表进行排序 


PNode MergeSList(PNode pHead1, PNode pHead2);                       // 合并两个有序单链表,合并后依然有序


int IsSListCross(PNode pHead1, PNode pHead2);                       // 判断两个单链表是否相交---链表不带环 


PNode GetCorssNode(PNode pHead1, PNode pHead2);                     // 求两个单链表相交的交点---链表不带环 
head.c
#include"head.h"

void PrintSListFromTail2Head(PNode pHead)                           // 逆序打印单链表 
{   
    assert(pHead);
    PNode pNewNode = pHead;

    if (NULL == pHead)
    {
        return;
    }
    else if (pNewNode)
    {
        PrintSListFromTail2Head(pNewNode->_pNext);
    }
    printf("%d", pNewNode->data);
    return;
}

void DeleteListNotTailNode(PNode pos)                               // 删除链表的非尾结点,要求:不能遍历链表 
{
    PNode p_Cur = pos->_pNext;
    pos->data =p_Cur->data;
    pos->_pNext = p_Cur->_pNext;
    free(p_Cur);
    p_Cur = NULL;
}

void InesrtPosFront(PNode pos, DataType data)                       // 在链表pos位置前插入值到data的结点 
{
    PNode p = pos->_pNext;                     //放置pos位置后面的指针
    pos ->_pNext = (PNode)BuyNewNode(pos->data);      //新建立的结点放在pos后面,并且新建立的结点的data是pos位置的data
    pos->_pNext->_pNext = p;                   //将原来pos后面的结点连接起来
    pos->data = data;                          //将需要插入的数据元素放在pos的位置

}

PNode FindMiddleNode(PNode pHead)                                  // 查找链表的中间结点,要求只能遍历一次链表 
{
    assert(pHead);
    if (NULL == pHead->_pNext )
    {
        return pHead;
    }
    PNode Fast = pHead;                        //建立一个快指针,每次走两步
    PNode Slow = pHead;                        //建立一个慢指针,一次走一步

    while (Fast && Fast->_pNext)               //判断元素个数是奇数和偶数时,返回中间结点
    {
        Fast = Fast->_pNext->_pNext;
        Slow = Slow->_pNext;
    }
    return Slow;                               //最后返回慢指针刚好走到中间结点
}

PNode FindLastKNode(PNode pHead, int K)                            // 查找链表的倒数第K个结点,要求只能遍历一次链表
{
    assert(pHead);
    if (NULL == pHead || K<=0)                                 //判空链表和输入的合法性
    {
        return NULL;
    }
    PNode Fast = pHead;
    PNode Slow = pHead;

    while (K--)
    {
        Fast = Fast->_pNext;                                  //快指针先向后走k步,然后慢指针和快指针一起以相同的速度向后走
    }

    while (Fast)
    {
        Fast = Fast->_pNext;
        Slow = Slow->_pNext;
    }
        return Slow;
}

PNode DeleteLastKNode(PNode pHead, int K)                          // 删除链表的倒数第K个结点,要求只能遍历一次链表 
{
    assert(pHead);
    if (NULL == pHead)
    {
        return NULL;
    }
    PNode Fast = pHead;
    PNode Slow = pHead;
    PNode Cur_Node = NULL;

    while (K--)
    {
        Fast = Fast->_pNext;                                  //快指针先向后走k步,然后慢指针和快指针一起以相同的速度向后走
    }

    while (Fast)
    {
        Fast = Fast->_pNext;
        Cur_Node = Slow;
        Slow = Slow->_pNext;
        Cur_Node->_pNext = Slow->_pNext;
    }
    return pHead;
}

void JosephCircle(PNode* pHead, const int M)                        // 用单链表实现约瑟夫环 
{
    PNode Cur_node = NULL;
    PNode Del_node = NULL;
    int count = 0;
    assert(pHead);
    if (NULL == pHead || M <= 0)
    { 
        return;
    }

    Cur_node = *pHead;
    while (Cur_node->_pNext)
    {
        Cur_node = Cur_node->_pNext;
    }
    Cur_node->_pNext = *pHead;
    Cur_node = *pHead;

    while (Cur_node->_pNext != Cur_node)
    {
        count = M;
        while (--count)
        {
            Cur_node = Cur_node->_pNext;
        }
        Del_node = Cur_node->_pNext;
        Cur_node->_pNext  = Del_node->_pNext;
        free(Del_node);
        Del_node = NULL;
    }

}

void ReverseSList(PNode* pHead)                                    // 链表的逆置--三个指针 
{
    PNode Pre_node = NULL;
    PNode Cur_node = NULL;
    PNode Next_node = NULL;
    assert(pHead);
    Cur_node = *pHead;
    while (Cur_node)
    {
        Pre_node = Cur_node;
        Cur_node = Cur_node->_pNext;
        Pre_node->_pNext = Next_node;
        Next_node = Pre_node;
    }
}   

PNode ReverseSListOP(PNode pHead)                                  // 链表的逆置--头插法 
{
    PNode Cur_node = NULL;
    PNode Next_node = NULL;
    assert(pHead);
    if (NULL == pHead || NULL == pHead->_pNext)
    {
        return NULL;
    }

    while (pHead)
    {
        Cur_node = pHead;
        pHead = pHead->_pNext;
        Cur_node->_pNext = Next_node;
        Next_node = Cur_node;
    }
    pHead = Next_node;

    return pHead;
}



void BubbleSort(PNode pHead)                                        // 用冒泡排序思想对单链表进行排序,从小到大排序
{
    PNode Tail = NULL;
    PNode P_Cur = pHead;
    int flag = 0;

    if (NULL == pHead || NULL == pHead->_pNext)
    {
        return;
    }

    while (Tail != pHead)                   //先判断单链表是否是有序的,按照排序结果,如果一趟排序,标记flag没有发生变化就直接打印单链表
    {
        P_Cur = pHead;
        flag = 0;
    }

    while (P_Cur!=Tail)
    {
        while (P_Cur->_pNext!=Tail)
        {
            if (P_Cur->data > P_Cur->data)
        {
            DataType tmp = P_Cur->data;
            P_Cur->data = P_Cur->_pNext->data;
            P_Cur->_pNext->data = tmp;
            flag = 1;
        }
            P_Cur = P_Cur->_pNext;
        }
        Tail = P_Cur;

        if (0 == flag)
        {
            return;
        }

    }
}

PNode MergeSList(PNode pHead1, PNode pHead2)                       // 合并两个有序单链表,合并后依然有序
{   
    PNode  P_NewNode = NULL;
    pHead1 = pHead1->_pNext;
    pHead2 = pHead2->_pNext;
    P_NewNode = pHead1;

    while (pHead1 && pHead2)                                    //两个链表首先都不为空,然后判断两个链表的data的大小
    {
        if (pHead1->data > pHead2->data)
        {
            P_NewNode = P_NewNode->_pNext;
            P_NewNode->data  = pHead2->data;
            pHead2 = pHead2->_pNext;
        }
        else
        {
            P_NewNode = P_NewNode->_pNext;
            P_NewNode->data  = pHead1->data;
            pHead1 = pHead1->_pNext;
        }
    }
    P_NewNode->_pNext = pHead1 ? pHead1 : pHead2;         //判断链表是否一个已经为空,直接将另一个链表的内容链接在后面
    free(pHead2);
    return P_NewNode;
}

int IsSListCross(PNode pHead1, PNode pHead2)                        // 判断两个单链表是否相交---链表不带环 
{
    PNode p1 = pHead1;
    PNode p2 = pHead2;
    int p1_Size = 0;                   //pHead1的大小,设置计数器计数
    int p2_Size = 0;                   //pHead2的大小,设置计数器计数
    int k = 0;                         //PHead1和PHead大小比较相差的步数

    if (NULL == p1 || NULL == p2)                               //判断链表是否为空,如果为空就返回0,所以不想交
    {                                    
        return 0;
    }

    while (p1)                                        //链表1不为空继续计数
    {
        p1_Size++;
        p1 = p1->_pNext;
    }
        while (p2)                                       //链表的大小
    {
    p2_Size++;
    p2 = p2->_pNext;
}

if (p1_Size > p2_Size)
{
    k = p1_Size - p2_Size;
    while (k--)
    {
        p1->_pNext;
    }
    p2->_pNext;
    if (p1->data == p2->data)
    {
        return 1;
    }
}

if (p1_Size < p2_Size)
{
    k = p2_Size - p1_Size;
    while (k--)
    {
        p2->_pNext;
    }
    p1->_pNext;
}
if (p1->data == p2->data)
{
    return 1;
}

}

PNode GetCorssNode(PNode pHead1, PNode pHead2)                     // 求两个单链表相交的交点---链表不带环
{   
    PNode p1 = pHead1;
    PNode p2 = pHead2;
    int p1_Size = 0;                   //pHead1的大小,设置计数器计数
    int p2_Size = 0;                   //pHead2的大小,设置计数器计数
    int k = 0;                         //PHead1和PHead大小比较相差的步数

    if (NULL == p1 || NULL == p2)                               //判断链表是否为空,如果为空就返回0,所以不想交
    {
        return NULL;
    }

    while (p1)                                        //链表1不为空继续计数
    {
        p1_Size++;
        p1 = p1->_pNext;
    }
    while (p2)                                       //链表的大小
    {
        p2_Size++;
        p2 = p2->_pNext;
    }

    if (p1_Size > p2_Size)
    {
        k = p1_Size - p2_Size;
        while (k--)
        {
            p1->_pNext;
        }
        p2->_pNext;
        if (p1->data == p2->data)
        {
            return p1;
        }
    }

    if (p1_Size < p2_Size)
    {
        k = p2_Size - p1_Size;
        while (k--)
        {
            p2->_pNext;
        }
        p1->_pNext;
    }
    if (p1->data == p2->data)
    {
        return p1;
    }
    else
    {
        return NULL;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值