C/C++中链表操作

1 篇文章 0 订阅
1 篇文章 0 订阅
本文总结了C/C++中链表操作的关键问题,包括如何找到链表的倒数第K个节点、判断链表是否存在环、找到链表的中间节点以及确定链表环的入口节点。这些问题都利用了前后指针的技巧来解决。
摘要由CSDN通过智能技术生成

C/C++中链表操作

刷面试宝典和剑指offer过程中,链表的操作是非常重要的一块儿,这里把遇到的问题汇总一下,值得注意的是,链表的很多技巧都是通过前后指针实现的。

(一)链表的倒数第K个节点(从1开始计数)

如果知道链表的长度len,就比较容易了,倒数第k个节点就是正数第len-k+1个节点,直接遍历就行了。如果len是未知的,当让也可以先遍历一次整个链表数出长度,然后在从头开始找到第len-k+1个,这样其实遍历了两次链表。
但是,能不能只遍历一次就找到倒数第k个节点呢。当然了,可以使用前后两个指针,开始时,前边的指针比后边的指针超前 K-1 步,然后两个指针同时向后移动,当前边的指针到达尾节点时,后边的指针指的就是倒数第k个节点。

struct Node{
    int v;
    Node* next;
};

Node* FindLastKth(Node* phead, int k){
    if(phead == NULL || k == 0)
        return NULL;
    //前后两个指针
    Node* pAhead = phead;
    Node* pBehind = phead;

    //pAhead先走k-1步
    for(int i = 0; i < k-1; i++){
        //
        if(pAhead->next != NULL)
            pAhead = pAhead->next;
        else
            return NULL;
    }

    //两个指针同时向后移动
    while(pAhead->next != NULL){
        pAhead = pAhead->next;
        pBehind = pBehind->next;
    }
    return pBehind;
}

有几处需要处理的细节:
1. 输入的链表为空
2. k为0,或者 k > len
3. 函数在特殊情况返回NULL,如果在主函数中有数出节点值的操作需要判断是否是NULL。

(二)链表中是否存在环

同样考虑前后(快慢)指针的技巧:一个指针每次走一步,另一个每次走两步,如过存在环,那么两个指针肯定能相遇;如果走的快的指针走到了尾节点两指针没有相遇,则不存在环。

bool HasCircle(Node* head){
    if(head == NULL)
        return false;

    Node* pFast = head;
    Node* pSlow = head;

    while(pFast->next != NULL){
        pFast = pFast->next;
        if(pFast->next != NULL){
            pFast = pFast->next;
            pSlow = pSlow->next;
            if(pFast == pSlow)
                break;
        }
        else
            break;
    }

    if(pFast == pSlow)
        return true;
    else
        return false;
}

(三)链表的中间节点

如果链表的节点个数是偶数,可以输出中间两个的任意一个。
这个问题同样可以使用快慢指针,一个指针每次走两步,另一个每次走一步。当快指针到达末尾时,慢指针指向的就是中间节点。

Node* Find_mid_node(Node* head){
    if(head == NULL)
        return NULL;
    Node* pAhead = head;
    Node* pBehind = head;
    while(pAhead->next != NULL){
        pAhead = pAhead->next;
        if(pAhead->next != NULL){
            pAhead = pAhead->next;
            pBehind = pBehind->next;
        }
    }
    return pBehind;
}

(四)链表中环的入口节点

一个链表中存在环,找出环的入口节点。
如果知道环中节点的个数n,可是使用前后指针,前边的指针先后n步,然后两个指针同时向前走。当两个指针相遇时,指向的就是环的入口节点。
怎么得到环中节点的个数呢?可以借鉴(三)的方法,找到环中的任意一个节点,然后用一个指针从该节点遍历,当再次遍历的该节点时,正好走了一圈,可以输出节点个数。

//找到环中的任意节点,如果不存在环,返回NULL
Node* Find_meet_node(Node* head){
    if(head == NULL)
        return NULL;

    Node* pFast = head;
    Node* pSlow = head;

    while(pFast->next != NULL){
        pFast = pFast->next;
        if(pFast->next != NULL){
            pFast = pFast->next;
            pSlow = pSlow->next;
            if(pFast == pSlow)
                break;
        }
        else
            break;
    }

    if(pFast == pSlow)
        return pFast;
    else
        return NULL;
}

//数环中节点个数,找到入口
Node* EntryOfCircle(Node* head){
    if(head == NULL)
        return NULL;

    Node* meetingNode = Find_meet_node(head);
    if(meetingNode == NULL)
        return NULL;
    //计数,环中节点个数
    int nums=1;
    Node* p = meetingNode;
    while(p->next != meetingNode){
        p = p->next;
        nums++;
    }

    //前后指针,遍历链表
    Node* pA = head;
    Node* pB = head;
    for(int i=0; i < nums; i++)
        pA = pA->next;
    while(pA != pB){
        pA = pA->next;
        pB = pB->next;
    }
    return pA;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值