C/C++中链表操作

原创 2016年05月30日 11:13:42

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;
}
版权声明:本文为博主原创文章,转载请注明出处!

相关文章推荐

C/C++单链表的一些操作

  • 2015年07月30日 21:27
  • 3.52MB
  • 下载

C/C++链表操作doc

  • 2010年04月24日 19:40
  • 49KB
  • 下载

c/c++单链表的创建和删除,插入,反转操作

链表是c/c++中的一个重要的数据结构 首先,他在物理存储上是非连续的,跟数组正好相反,数组是一系列连续的存储单元,这样的特性可能会使链表的访问时间复杂度O(n)高于数组O(1),但是对于链表的插入操...

c/c++简单的链表操作

  • 2010年06月14日 10:39
  • 21KB
  • 下载

C/C++单链表的一些操作

LINK_List.h#pragma once #include #include using namespace std;typedef struct Nodex{ char s_ch; ...

详细的单链表基本操作C/C++实现

#include #include #include #include using namespace std; typedef struct snode { int data; ...

C/C++ 知识回顾 单链表基本操作

单链表基本操作,包括:创建,插入,删除,排序,倒置

C/C++面试(4)——链表操作

比较常见面试题目: 1.不带头结点的链表逆序 2.给任意一个结点,在不遍历链表的情况下,删除该节点 参考链接:http://blog.csdn.net/csufuyi/article/details/...

C单链表的基本操作

  • 2012年10月22日 08:11
  • 4KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C/C++中链表操作
举报原因:
原因补充:

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