Data structure (2): Linked list and algorithms for interviews

1. Introduction to Linked List

1. Definition

The linked list is a discontinuous and non-sequential storage structure on the physical storage unit . The logical order of the data elements is realized through the pointer address of the linked list. Each element contains two nodes, one is the data field (memory space) for storing elements, The other is a pointer field pointing to the address of the next node . The pointer field of the last node points to null (meaning null pointer). The entry node of the linked list is called the head node of the linked list, which is head.

// 单链表
struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

Linked lists are commonly used to implement file systems, hash tables, and adjacency lists. There are two types of linked lists: singly linked list and doubly linked list.

2. Advantages and disadvantages and usage scenarios

Advantages : Easy to add and delete data.

Disadvantages : Access is time-consuming.

Applicable scenarios : Scenarios where the amount of data is small and frequent addition and deletion operations are required.

The comparison list of array and linked list data structures is as follows:

3. CRUD

Data access : Because the data is stored in a decentralized manner, if you want to access the data, you can only start from the first data and go down one by one according to the pointer.

Data addition : Change the position pointed by the pointer of Blue to Green, and then point the pointer of Green to Yellow.

 

Data deletion : Just change the pointing of the pointer. For example, to delete Yellow, you only need to change the position pointed by the Green pointer from Yellow to Red.

Although Yellow itself is still stored in memory, this data cannot be accessed from anywhere, so there is no need to delete it. If you need to use the storage space of Yellow in the future, just overwrite it with new data.

 

4. Basic operation of linked list

1) InsertAtEnd--Insert the specified element at the end of the linked list.

2) InsertAtHead--Insert the specified element at the beginning/head of the linked list.

3) Delete--Delete the specified element from the linked list.

4) DeleteAtHead--Delete the first element of the linked list.

5) Search--returns the specified element from the linked list.

6) isEmpty--If the linked list is empty, it returns true.

2. Common test algorithm

1. Reverse linked list

Example: Input: 1->2->3->4->5->NULL Output: 5->4->3->2->1->NULL.

Idea : first define a cur pointer to point to the head node, define a pre pointer, and initialize it to null. Then use the temp pointer to save the cur->next node, and point cur->next to pre to complete the reversal. Loop through nodes until cur points to null.

//反转链表--双指针法
linkedNode* reverseLink(linkedNode* head){
    linkedNode* temp;
    linkedNode* cur = head;
    linkedNode* pre = NULL;
    while(cur){
        temp = cur->next;
        cur->next = pre;
        pre = cur;
        cur = temp;
    }
    return pre;
}

linkedNode* reverse(linkedNode* pre, linkedNode* cur){
    if(cur == NULL) return pre;
    linkedNode* temp = cur->next;
    cur->next = pre;
    // 可以和双指针法的代码进行对比,如下递归的写法,其实就是做了这两步
    // pre = cur;
    // cur = temp;
    return reverse(cur,temp);
}

// 反转链表--递归法1 从前往后翻转指针指向
linkedNode* reverseLink2(linkedNode* head){
    // 和双指针法初始化是一样的逻辑
    // ListNode* cur = head;
    // ListNode* pre = NULL;
    return reverse(NULL, head);
}


// 反转链表--递归法2 从后往前翻转指针指向
linkedNode* reverseLink3(linkedNode* head){
    //边缘条件判断
    if(head == NULL) return NULL;
    if(head->next == NULL) return head;

    // 递归调用,翻转第二个节点开始往后的链表
    linkedNode* last = reverseLink3(head->next);
    head->next->next = head;
    head->next = NULL;
    return last;
}

 

2. Detect cycles in linked lists

Title: Input: 3->2->0->-4->2, output: tail connects to node 2.

leecode: circular linked list, mainly examines two knowledge points.

1) Determine whether the linked list has a ring. 2) If there is a ring, how to find the entrance of this ring.

Idea: Determine whether the linked list has a ring. You can use the fast and slow pointer method to define fast and slow pointers respectively. Starting from the head node, the fast pointer moves two nodes at a time, and the slow pointer moves one node at a time. If the fast and slow pointers meet on the way, it means that the linked list has a ring.

If there is a ring, how to find the entrance to the ring. A pointer is started from the head node, and a pointer is also started from the meeting node. These two pointers only go to one node at a time, so when the two pointers meet, it is the node of the ring entrance .

#include<iostream>
using namespace std;

struct linkNode{
    int val;
    linkNode* next;
    linkNode(int x):val(x),next(NULL){};
};

// 双指针
linkNode* detectCycle(linkNode* head){

    linkNode* fast = head;
    linkNode* slow = head;
    while(fast != NULL && fast->next != NULL){
        fast = fast->next->next;
        slow = slow->next;

        if(fast == slow){

            linkNode* index1 = fast;
            linkNode* index2 = head;
            while (index1 != index2)
            {
                index1 = index1->next;
                index2 = index2->next;
            }
            return index1;
        }
    }
    return NULL;
}

void printLink(linkNode* head){
    while(head != NULL){
        cout<<head->val<<" ";
        head = head->next;
    }
    cout<<endl;
}

int main(){
    linkNode* n1 = new linkNode(3);
    linkNode* n2 = new linkNode(2);
    n1->next = n2;
    linkNode* n3 = new linkNode(0);
    n2->next = n3;
    linkNode* n4 = new linkNode(-4);
    n3->next = n4;
    n4->next = n2;
    //循环打印链表3->2->0->-4->2->0->-4->...
    printLink(n1);
    linkNode* res = detectCycle(n1);
    cout<<"tail connects to node "<< res->val;
}

 

3. Return the last Nth node of the linked list.

Input: 1->2->3->4->5, n=3. Output: 3.

Idea: define the fast and slow pointers slow, fast, start slow = fast = head; then only fast walks backwards, starting with n steps, fast and slow walk at the same time; finally fast to the end, slow is the last nth.

#include<iostream>
using namespace std;

struct linkedNode{
    int val;
    linkedNode* next;
    linkedNode(){};
    linkedNode(int x):val(x),next(NULL){};
    
};

// 双指针
int returnNthfromEnd(linkedNode* head, int n){
    linkedNode* slow = head;
    linkedNode* fast = head;
    while(n-- && fast!=NULL){
        fast = fast->next;
    }
    while(fast != NULL){
        slow = slow->next;
        fast = fast->next;
    }
    return slow->val;

}

linkedNode* initLink(){
    linkedNode* dummyNode = new linkedNode(0);
    linkedNode* tmp = dummyNode;
    for(int i =0; i<5;i++){
        linkedNode* newNode = new linkedNode();
        newNode->val = i+1;
        newNode->next = NULL;
        tmp->next = newNode;
        tmp = tmp->next;
    }
    return dummyNode->next;
}

int main(){
    linkedNode* res = initLink();
    printLink(res);
    int n = 4;
    int result = returnNthfromEnd(res,n);
    cout << result;

}

4. Delete duplicates in the sorted linked list

Input: 3->3->5->5->8. Output: 3->5->8.

#include<iostream>
using namespace std;

struct linknode
{
    int val;
    linknode* next;
    linknode(int x): val(x), next(NULL){};
};

void printLink(linknode *Head){
    while(Head != NULL){
        cout << Head->val << " ";
        Head = Head->next;
    }
    cout << endl;
}

linknode* removeRepeatNode(linknode *head){
    if(NULL == head) return head;
    linknode * cur = head;
    while(cur->next != NULL){
        if(cur->val == cur->next->val)
            cur->next = cur->next->next;
        else cur = cur->next;
    }
    return head;
}

int main(){
    linknode *n1 = new linknode(3);
    linknode *n2 = new linknode(3);
    linknode *n3 = new linknode(5);
    linknode *n4 = new linknode(5);
    linknode *n5 = new linknode(8);
    n1->next = n2;
    n2->next = n3;
    n3->next = n4;
    n4->next = n5;
    printLink(n1);
    linknode *result = removeRepeatNode(n1);
    printLink(result);
}

 

 

Guess you like

Origin blog.csdn.net/bb8886/article/details/129938535