Data structure learning_01_single linked list_intersecting linked list_rings of linked list

1 Concept and definition of linked list

链表(Linked List)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。
如下图:

Insert picture description here
Because it does not have to be stored in order, the linked list can reach O(1) complexity when inserting, which is much faster than another linear table-the sequential table, but it takes O( to find a node or access a specific number of nodes n) time, and the corresponding time complexity of the sequence table is O(log n) and O(1) respectively.
Using the linked list structure can overcome the disadvantage that the data size of the array linked list needs to be known in advance. The linked list structure can make full use of the computer memory space and realize flexible dynamic memory management. However, the linked list loses the advantage of random reading of the array, and the linked list has a relatively large space overhead due to the increase of the pointer field of the node.
In computer science, linked lists can be used to generate other types of data structures as a basic data structure. A linked list usually consists of a series of nodes, each node contains arbitrary instance data (data fields) and one or two links that point to the location of the previous/or next node. The most obvious advantage of the linked list is that the arrangement of the related items in the conventional array may be different from the order of these data items on the memory or on the disk, and the data access often has to be converted in a different arrangement order. The linked list is a self-indicating data type because it contains a pointer (link) to another data of the same type.
The linked list allows inserting and removing nodes at any position on the list, but does not allow random access. There are many different types of linked lists: singly linked lists, doubly linked lists and circular linked lists.
Linked lists can usually be derived from circular linked lists, static linked lists, double-linked lists, etc. For the use of linked lists, you need to pay attention to the use of head nodes.

2 Intersecting linked list

When the linked list is intersected, it has a Y shape and no X shape. As shown in the figure below,
Insert picture description here
Insert picture description here
what is the reason? Because a node can be pointed to by the next pointer of multiple nodes at the same time, but the next pointer of a node cannot point to multiple nodes at the same time. Simply put, it can be many-to-one, but not one-to-many.
The code and analysis ideas are as follows:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 //明确相交链表只能是Y形状,绝对不能是X形状,因为一个节点可以被多个节点指向,但是一个节点不能指向多个节点。
typedef struct ListNode Node;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    
    
    int lenA = 0;
    int lenB = 0;
    Node* curA = headA;
    Node* curB = headB;
    //计算出链表A和B的长度
    while(curA)
    {
    
    
        lenA++;
        curA=curA->next;
    }
    while(curB)
    {
    
    
        lenB++;
        curB = curB->next;
    }
    //让长链表先走,先走的距离为两个链表的长度的差,达到二者在同一位置的目的,然后两个同时走并相互比较直到找到相交节点
    int gap = abs(lenA-lenB);

    Node *longList = headA,*shortList = headB;
    if(lenA<lenB)
    {
    
    
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
    
    
        longList = longList->next;
    }
    while(longList && shortList)//此时longList和shortList是同样长链表的头节点,所以只放一个就可以了,当然&&上另一个也没撒问题
    {
    
    
        if(longList==shortList)
        {
    
    
            return longList;//return shortList->next也可以
        }
        else
        {
    
    
            longList  = longList->next;
            shortList = shortList->next;
        }
    }

    return NULL;
}


3 Linked list with ring

3.1 How to judge whether a linked list has a ring

If there is a node in the linked list that can be reached again by continuously tracking the next pointer, then there is a ring in the linked list.
The linked list shown in the figure below has a ring. If you try to traverse it, you will find an endless loop.
Insert picture description here
Insert picture description here
So how do you judge whether a given linked list has a ring?
In fact, we can define two pointers, one is slow and the other is fast. They are slow, fast, slow and take two steps at a time. The analysis process and proof are as follows: The
Insert picture description here
Insert picture description here
code is as follows:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode Node;
bool hasCycle(struct ListNode *head) {
    
    
    Node* slow = head;
    Node* fast = head;

    while(fast && fast->next){
    
    
        slow = slow->next;
        fast = fast->next->next;

        if(slow == fast){
    
    
            return true;
        }
    }
    return false;
}

//如何证明呢?
//画图说明slow一次走一步,fast一次走2步,fast和slow进入环后,二者
//之间的距离为X,则快慢指针之间的距离会一直缩小,指导二者相遇
//证明了只有链表有环才存在这种情况。

3.2 Find the first node of the linked list into the ring

As soon as the method is shown in the figure below:
Insert picture description here
the meeting node in the ring is disconnected, and the problem is converted to the problem of finding the intersection node of the blue linked list and the brown linked list.
Insert picture description here
The code is implemented as follows:

//第一种方法
//快慢指针进入环后,二者终会相遇,再相遇节点处断开链表然后就是两个
//链表,此时问题就转换成了求两个链表的相交节点
typedef struct ListNode Node;
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        //先找到在环中的相遇节点
        Node* slow = head;
        Node* fast = head;
        while(fast && fast->next){
    
    
            slow = slow->next;
            fast = fast->next->next;
            if(slow==fast){
    
    
                break;
            }
        }
        //如果此时程序进入到if中证明链表无环
        if(fast==NULL || fast->next==NULL){
    
    
            return NULL;
        }
        Node* head1 = head;
        //断开链表
        Node* head2 = slow->next;
        slow->next = NULL;
      
       return getIntersectionNode(head1,head2);


    }
    //求两个链表的相交节点的方法
    struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    
    
    int lenA = 0;
    int lenB = 0;
    Node* curA = headA;
    Node* curB = headB;
    //计算出链表A和B的长度
    while(curA)
    {
    
    
        lenA++;
        curA=curA->next;
    }
    while(curB)
    {
    
    
        lenB++;
        curB = curB->next;
    }
    //让长链表先走,先走的距离为两个链表的长度的差,达到二者在同一位置的目的,然后两个同时走并相互比较直到找到相交节点
    int gap = abs(lenA-lenB);

    Node *longList = headA,*shortList = headB;
    if(lenA<lenB)
    {
    
    
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
    
    
        longList = longList->next;
    }
    while(longList && shortList)//此时longList和shortList是同样长链表的头节点,所以只放一个就可以了,当然&&上另一个也没撒问题
    {
    
    
            if(longList==shortList)
            {
    
    
                return longList;//return shortList->next也可以
            }
            else
            {
    
    
                longList  = longList->next;
                shortList = shortList->next;
            }
    }

    return NULL;
 }
};
 


 //第一种方法的变形
 //快慢指针进入环后,二者终会相遇,再相遇节点处逻辑上断开链表其实没有断开,slow->next作为新的头,在计算长度的时候,lenA= lenB
 //要初始化为1
 //链表,此时问题就转换成了求两个链表的相交节点
typedef struct ListNode Node;
struct ListNode *detectCycle(struct ListNode *head) {
    
    
    if(head == NULL){
    
    
        return NULL;
    }
    Node* slow = head;
    Node* fast = head;
    while(fast && fast->next){
    
    
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast){
    
    
            break;
        }
    }
    //此时找到二者相遇的节点slow == fast
    if(fast==NULL || fast->next == NULL){
    
    
        return NULL;
    }

    //定义逻辑上两个链表的头节点
    Node* curA = head;

    Node* newHead = slow->next;
    Node* curB = newHead;
    
    int lenA = 1;
    int lenB = 1;

    while(curA != slow){
    
    
        lenA++;
        curA= curA->next;
    }
    while(curB != slow){
    
    
        lenB++;
        curB = curB->next;
    }

    int gap = abs(lenA - lenB);

    Node* longerList = head;
    Node* shortList = newHead;

    if(lenA < lenB){
    
    
        longerList = newHead;
        shortList = head;
    }

    while(gap--){
    
    
        longerList = longerList->next;
    }
   //此时long和short链表在同一起跑线上
    while(longerList){
    
    //while(shortList)
         if(longerList == shortList){
    
    
             return longerList;
         }else{
    
    
             longerList = longerList->next;
             shortList = shortList->next;
         }
    }

    return NULL;

}

Method 2: More difficult to understand, need reasoning and proof. The
process is as follows:
Insert picture description here
Code implementation:

//方法2:需要推导和证明
//快慢指针加高中物理的相遇问题
typedef struct ListNode Node;
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        //先找到在环中的相遇节点
        Node* slow = head;
        Node* fast = head;
        while(fast && fast->next){
    
    
            slow = slow->next;
            fast = fast->next->next;
            if(slow==fast){
    
    
                break;
            }
        }
        //如果此时程序进入到if中证明链表无环
        if(fast==NULL || fast->next==NULL){
    
    
            return NULL;
        }
        
        Node* meet  = slow;

        while(head!=meet){
    
    
            head=head->next;
            meet = meet->next;
        }
       return meet;


    }

};

It's over here, do you understand.

Guess you like

Origin blog.csdn.net/CZHLNN/article/details/111768567