链表操作详解(C++)

1.结构体

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

2.链表头部插入

Node * Insert_head(Node * & head, int value)
{
    Node * p = new Node;
    p->data = value;

    if(head == NULL)
    {
        head = p;
        head->next = NULL;
    }
    else
    {
        p->next = head;
        head = p;
    }
    return head;
}

3.链表尾部插入

Node * Insert_End(Node * & head, int value)
{
    Node * q = head;
    Node * p = new Node;
    p->data = value;

    if(head == NULL)
    {
        head = p;
        head->next = NULL;
    }
    else 
    {
        while(q->next != NULL)
        {
            q = q->next;
        }
        q->next = p;
    }
    return head;
}

4.链表打印

void PrintList(Node * head)
{
    Node * p = head;

    while(p!=NULL)
    {
        cout << p->data << endl;
        p=p->next;
    }
}

5.获取链表长度

int GetLength(Node * head)
{
    Node * p = head;

    int len = 0;

    while(p != NULL)
    {
        p = p->next;
        len++;
    }

    return len;
}

6.链表插入


Node * Insert(Node *& head, int value)
{
    Node * p0, *p1, *p2;

    p0 = new Node;
    p0->data = value;

    p1 = head;

    if(head == NULL)
    {
        head = p0;
        head->next = NULL;

        return head;
    }

    //找到插入的位置
    while(p0->data > p1->data && p1->next != NULL)
    {
        p2 = p1;
        p1 = p1->next;
    }

    if(p0->data <= p1->data)
    {
        if(p1 == head)
        {
            //头部插入
            p0->next = head;
            head = p0;
        }
        else
        {   
            //中间插入
            p2->next = p0;
            p0->next = p1;
        }
    }
    else
    {
        //尾部插入
        p1->next = p0;
        p0->next = NULL;
    }

    return head;
}

7.链表删除

Node * Delete(Node * head, int value)
{
    Node * p, *q;

    p = head;

    while(p->data != value && p->next != NULL)
    {
        q = p;
        p = p->next;
    }

    if(p->data == value)
    {
        if(p == head)
        {
            head = p->next;
            delete p;
        }
        else
        {
            q->next = p->next;
            delete p;
        }
    }   
    else
    {
        cout << "not find data" << endl;
    }

    return head;
}

8.链表清空

void Destruct(Node * head)
{
    Node *p, *q;
    
    p = head;
    q = NULL;

    while(p!=NULL)
    {
        q = p;
        p = p->next;

        delete q;
    }
}

9.链表逆序(循环方法)

Node * ReverseList(Node * head)
{
    Node *p, *q, *r;

    p = head;        //一开始p指向第一个节点
    q = p->next;     //q指向第二个节点
    while(q != NULL) //如果没到链尾
    {                //以第一次循环为例
        r = q->next; //r暂时存储第三个节点
        q->next = p; //没有执行这句前,q->next指向第三个节点

        p = q;       //执行之后p指向第二个节点   
        q = r;       //之后p指向第二个节点
    }

    head->next = NULL; //最后原来的链头变为链尾
    head = p;        //原来的链尾变成链头
    
    return head;
}

10.链表逆序(递归方法)

将链表分为当前表头节点和其余节点,递归的思想就是,先将当前的表头节点从链表中拆出来,然后对剩余的节点进行逆序,最后将当前的表头节点连接到新链表的尾部,这里边的关键点是头节点head的下一个节点head->next将是逆序后的新链表的尾节点,也就是说,被摘除的头接点head需要被连接到head->next才能完成整个链表的逆序


Node * ReverseList1(Node * head)
{
    if(head == NULL || head->next == NULL)
    {
        return head;
    }

    Node* list = ReverseList1(head->next);
	
	// 将当前节点的下一个节点的指针指向当前节点,实现逆转
    head->next->next = head;
    head->next = NULL;

    return list ;
}

11.两个链表有序合并后依然有序(循环方法)

Node * Merge(Node * head1, Node * head2)
{
    Node * head = NULL;

    if(head1 == NULL)
    {
        return head2;
    }

    if(head2 == NULL)
    {
        return head1;
    }

    if(head1->data <= head2->data)
    {
        head = head1;
        head1 = head1->next;
    }
    else
    {
        head = head2;
        head2 = head2->next;
    }

    Node * temp = head;

    while(head1 != NULL && head2 != NULL)
    {
        if(head1->data <= head2->data)
        {
            temp->next = head1;
            head1 = head1->next;
            temp = temp->next;
        }
        else
        {
            temp->next = head2;
            head2 = head2->next;
            temp = temp->next;
        }
    }    

    if(head1 == NULL)
    {
        temp->next = head2;
    }

    if(head2 = NULL)
    {
        temp->next = head1;
    }

    return head;
}

12.两个链表有序合并后依然有序(递归方法)


Node * MergeRecursive(Node * head1, Node * head2)
{
    Node * head = NULL;

    if(head1 == NULL)
    {   
        return head2;
    }

    if(head2 == NULL)
    {
        return head1;
    }

    if(head1->data < head2->data)
    {
        head = head1;
        head->next = MergeRecursive(head1->next, head2);
    }
    else
    {
        head = head2;
        head->next = MergeRecursive(head1, head2->next);
    }

    return head;
}

13.判断一个链表是否有环

bool ExitLoop(Node * head)
{
    Node * Fast = head;
    Node * Slow = head;

    while(Fast != NULL && Fast->next != NULL)
    {
        Fast = Fast->next->next;
        Slow = Slow->next;

        if(Fast == Slow)
        {
            return true;
        }
    }

    return false;
}

14.找到环的入口点

从链表起点head开始到入口点的距离,与从slow和fast的相遇点到入口点的距离相等

Node * FindLoopStart(Node * head)
{
    Node * Fast = head;
    Node * Slow = head;

    while(Fast != NULL && Fast->next != NULL)
    {
        Fast = Fast->next->next;
        Slow = Slow->next;

        if(Fast == Slow)
        {
            break;
        }
    }

    if(Fast == NULL || Fast->next == NULL)
    {
        return NULL;
    }

    Node * p1 = head;
    Node * p2 = Slow;

    while(p1 != p2)
    {
        p1 = p1->next;
        p2 = p2->next;
    }

    return p1;
}

15.环上节点个数

slow和fast的相遇后,Slow再走一圈就是环的长度

int GetLoopLength(Node * head)
{
    Node * Fast = head;
    Node * Slow = head;

    while(Fast != NULL && Fast->next != NULL)
    {
        Fast = Fast->next->next;
        Slow = Slow->next;

        if(Fast == Slow)
        {
            break;
        }
    }

    if(Fast == NULL || Fast->next == NULL)
    {
        return 0;
    }

    Node * p = Slow->next;
    int len = 1;

    while(p != Slow)
    {
        p = p->next;
        len++;
    }

    return len;
}

16.判断两个链表是否相交并找出交点

Node * Find_Node(Node * head1, Node * head2)
{
    if(head1 == NULL || head2 == NULL)
    {
        return NULL;
    }

    Node * p1 = head1;
    Node * p2 = head2;

    int len1 = 0;
    int len2 = 0;

    while(p1->next != NULL)
    {
        len1++;
        p1 = p1->next;
    }

    while(p2->next != NULL)
    {
        len2++;
        p2 = p2->next;
    }

    //不相交
    if(p1 != p2)
    {
        return NULL;
    }

    int diff = abs(len1 - len2);

    if(len1 > len2)
    {
        p1 = head1;
        p2 = head2;
    }
    else
    {
        p1 = head2;
        p2 = head1;
    }

    for(int i=0; i<diff; i++)
    {
        p1 = p1->next;
    }

    while(p1 != p2)
    {
        p1 = p1->next;
        p2 = p2->next;
    }
    
    return p1;
}
在双指针遍历的过程中,如果一个指针达到链表末尾后,将其重定向到另一个链表的头部,
这就保证了两个指针在相遇点相遇。这个方法不受链表长度差异的影响。
Node * getIntersectionNode(Node* head1, Node* head2)
{
  if (head1 == NULL || head2 == NULL) {
    return NULL;
  }

  Node* p1 = head1;
  Node* p2 = head2;

  while (p1 != p2)
  {
    p1 = p1==NULL? p2:p1->next;
    p2 = p2==NULL? p1:p2->next;
  }
  
  return p1;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值