Handwritten C++ to implement reversal, deletion and merging of linked lists

Table of contents

1. C++ implements linked list member methods

1.1 Print linked list

1.2 Delete linked list nodes

1.3 The k-th node from the last in the linked list

1.4 Reverse linked list

1.5 Merge two sorted linked lists

2. The complete code of the linked list


Previous article"Handwritten Linked List C++"

1. C++ implements linked list member methods

        In the previous blog "Handwritten Linked List C++", the basic List class was implemented. In interviews, we are often asked how to reverse List, delete elements, etc., and also to enrich the members of the List class; in this section, this article implements list operations such as the title.

        C++ linked list, an important data structure, consists of a series of nodes. Each node contains two parts: data and a pointer to the next node. A linked list is a non-continuous and non-sequential storage structure on a physical storage unit. The logical order of the data structure is realized through the link order of pointers in the linked list. The simplest form of a linked list is a one-way linked list, which contains only an information field and a pointer field. The advantage of a linked list is that it can dynamically allocate memory space and achieve efficient data operations. In C++, each node of a linked list is linked together through a pointer, forming a continuous linked structure.

1.1 Print linked list

In order to facilitate debugging the code, first write a function that prints the linked list:

void List::print()
{
    if (size_ == 0)
    {
        cout << "size = 0" << endl;
        return;
    }
    //遍历
    Node* p_curr = head_->next_;//【注意这里next】
    while (p_curr != nullptr)
    {
        cout << p_curr->data_ << " ";
        p_curr = p_curr->next_;
    }
    cout << endl;
}

1.2 Delete linked list nodes

The idea is to find the previous node of the Node to be deleted and let the pointer of the previous node point to the next node of the Node.

For example: when pos = 3, the for loop is executed, p_curr represents the node address with an index value of 2, and then we let p_curr->next point to the next node of the next node.

//功能:删除索引位置为pos的节点
void List::remove(int pos)
{
    if (pos < 0 || pos > size_)
    {
        return;
    }
    Node* p_curr = head_;
    for (int i = 0; i < pos; i++)// 3
    {
        p_curr = p_curr->next_;
    }
    p_curr->next_ = p_curr->next_->next_;
    size_--;
}

1.3 The k-th node from the last in the linked list

You can take a look at the method on Jianzhi offer. I maintain a size_ in the List class here, so it is relatively simple.

//链表中倒数第k个节点
int List::get_reverse_element(int reverse_pos)
{
    int pos = size_ - reverse_pos;
    Node* p_curr = head_;
    for (int i = 0; i < pos; i++)
    {
        p_curr = p_curr->next_;
    }
    return p_curr->data_;
}

1.4 Reverse linked list

This method is a must-learn, as it is often asked during interviews and even requires hand shredding on the spot.

//反转链表
void List::reverse()
{
    // head   -> 1 -> 2 -> 3 -> 4 -> nullptr
    //nullptr <- 1 <- 2 <- 3 <- 4

    Node* p_curr = head_->next_;
    Node* p_prev = nullptr;
    while (p_curr != nullptr)
    {
        Node* p_next = p_curr->next_;
        if (p_next == nullptr)
        {
            head_->next_ = p_curr;
        }
        p_curr->next_ = p_prev;
        p_prev = p_curr;
        p_curr = p_next;
    }
}

The picture below shows the inversion effect:

ec73148a7a4b46bf85b735c511905637.png

1.5 Merge two sorted linked lists

//合并两个排序链表
void mergeLists(List& list3, List& list4, List& list34)
{
    Node* p_curr3 = list3.head_->next_;
    Node* p_curr4 = list4.head_->next_;
    Node* p_curr34 = list34.head_->next_;
    int location = 0;
    while ((p_curr3 != nullptr) || (p_curr4 != nullptr))
    {
        if ((p_curr3 != nullptr) && (p_curr4 != nullptr))
        {
            if (p_curr3->data_ < p_curr4->data_)
            {
                list34.insert(location, p_curr3->data_);
                location++;
                list34.insert(location, p_curr4->data_);
                location++;
            }
            else
            {
                list34.insert(location, p_curr4->data_);
                location++;
                list34.insert(location, p_curr3->data_);
                location++;
            }
            p_curr3 = p_curr3->next_;
            p_curr4 = p_curr4->next_;
        }
        else if ((p_curr3 != nullptr) && (p_curr4 == nullptr))
        {
            list34.insert(location, p_curr3->data_);
            location++;
            p_curr3 = p_curr3->next_;
        }
        else if ((p_curr3 == nullptr) && (p_curr4 != nullptr))
        {
            list34.insert(location, p_curr4->data_);
            location++;
            p_curr4 = p_curr4->next_;
        }
    }
}

For example, there are two ascending sequences:

  • A:0 2 4 6 8 14                                                                                                       
  • B:1 3 5 7 9 12 21 31 

To turn them into an ordinal sequence;

Idea: Assume that the number of elements in the two sequences is equal; we compare 0 1 to get 0 1, and then compare 1 and 2 3 to get 0 1 2 3; then Compare 3 and 4 5; and so on, (corresponding to line 10 of code)

Now consider A sequence length > B sequence length; corresponding to the 29th line of code; A sequence length < B sequence length; corresponding to the 35th line of code above.

//合并两个排序链表
    List list3,list4;
    for (int i = 0; i < 5; i++)
    {
        list3.insert(i, 2*i);
        list4.insert(i, 2 * i + 1);
    }
    list3.insert(5, 14);
    list4.insert(5, 12);
    list4.insert(6, 21);
    list4.insert(7, 31);
    list3.print();
    list4.print();

    List list34;
    mergeLists(list3, list4, list34);
    list34.print();

Test case:

216e44bc448d4c09785c6037589f395b.jpeg

2. The complete code of the linked list

The following code includes: List implementation, node definition, insertion, deletion, merging, reversal of linked list, etc.

#include<iostream>
using namespace std;

class Node
{
public:
    int data_;//数据阈
    Node* next_;//指针阈
public:
    Node() :data_(-1), next_(nullptr) {}
};

class List
{
public:
    List()
    {
        this->head_ = new Node();// 不分配空间,下面赋值是不合理的!
                                 //this->head_->data_ = 0;//多余?
        this->head_->next_ = nullptr;
        this->size_ = 0;
    };
    void insert(int pos, int value);
    void remove(int pos);
    int get_reverse_element(int reverse_pos);//链表中倒数第k个节点
    void reverse();

    int operator[](int i);
    void print();
    ~List();
public:
    Node* head_;
    int size_;//维护一个size
};
//在第pos个元素前一个位置插入(创建、找到位置、入链表)
void List::insert(int pos, int value)
{
    if (pos < 0 || pos > size_)
        return;

    //创建新的节点接受数据
    Node* newnode = new Node();
    newnode->data_ = value;
    //cout << "newnode->data_ = " << *newnode->data_ << endl;
    newnode->next_ = nullptr;

    //利用辅助指针找到pos前一个节点
    // 其实这里不断next,无非就是希望p_curr = nullptr
    // 然后56行 让newnode->next_  = nullptr(这个nullptr是从head_->next 传过来的);也就是尾部插入嘛
    // 而循环链表 同理 让newnode->next_  = &(head_)(这个 &(head_) 是从head_->next 传过来的);
    Node* p_curr = head_;
    for (int i = 0; i < pos; i++) //这个for循环本质上是head_->next_->next_......
    {
        p_curr = p_curr->next_;
    }
    //现在p_curr就是pos前一个节点的指针阈
    //新节点入链表
    newnode->next_ = p_curr->next_;//右边
    p_curr->next_ = newnode;//左边
    size_++;
}

void List::remove(int pos)
{
    if (pos < 0 || pos > size_)
    {
        return;
    }
    Node* p_curr = head_;
    for (int i = 0; i < pos; i++)// 3
    {
        p_curr = p_curr->next_;
    }
    p_curr->next_ = p_curr->next_->next_;
    size_--;
}

//链表中倒数第k个节点
int List::get_reverse_element(int reverse_pos)
{
    int pos = size_ - reverse_pos;
    Node* p_curr = head_;
    for (int i = 0; i < pos; i++)
    {
        p_curr = p_curr->next_;
    }
    return p_curr->data_;
}

//反转链表
void List::reverse()
{
    // head   -> 1 -> 2 -> 3 -> 4 -> nullptr
    //nullptr <- 1 <- 2 <- 3 <- 4

    Node* p_curr = head_->next_;
    Node* p_prev = nullptr;
    while (p_curr != nullptr)
    {
        Node* p_next = p_curr->next_;
        if (p_next == nullptr)
            if (p_curr->next_ == nullptr)
            {
                head_->next_ = p_curr;
            }
        p_curr->next_ = p_prev;
        p_prev = p_curr;
        p_curr = p_next;
    }
}

int List::operator[](int i)
{
    Node* p_curr = head_;
    int count = 0;
    while (count <= i)
    {
        p_curr = p_curr->next_;
        count++;
    }
    return p_curr->data_;
}
void List::print()
{
    if (size_ == 0)
    {
        cout << "size = 0" << endl;
        return;
    }
    //遍历
    Node* p_curr = head_->next_;//【注意这里next】
    while (p_curr != nullptr)
    {
        cout << p_curr->data_ << " ";
        p_curr = p_curr->next_;
    }
    cout << endl;
}
List::~List()
{
    while (size_ != 0)
    {
        Node* p_curr = head_;
        for (int i = 0; i < (size_ - 1); i++)// 012345 i < 5
        {
            p_curr = p_curr->next_;//for循环执行完,p_curr指向4
        }
        delete p_curr->next_;//删除最后一个元素
        p_curr->next_ = nullptr;//末尾元素 空指针
        size_--;
        print();
    }
    delete head_; //【这个容易忘记!】
    cout << "delete!" << endl;
}

//合并两个排序链表
void mergeLists(List& list3, List& list4, List& list34)
{
    Node* p_curr3 = list3.head_->next_;
    Node* p_curr4 = list4.head_->next_;
    Node* p_curr34 = list34.head_->next_;
    int location = 0;
    while ((p_curr3 != nullptr) || (p_curr4 != nullptr))
    {
        if ((p_curr3 != nullptr) && (p_curr4 != nullptr))
        {
            if (p_curr3->data_ < p_curr4->data_)
            {
                list34.insert(location, p_curr3->data_);
                location++;
                list34.insert(location, p_curr4->data_);
                location++;
            }
            else
            {
                list34.insert(location, p_curr4->data_);
                location++;
                list34.insert(location, p_curr3->data_);
                location++;
            }
            p_curr3 = p_curr3->next_;
            p_curr4 = p_curr4->next_;
        }
        else if ((p_curr3 != nullptr) && (p_curr4 == nullptr))
        {
            list34.insert(location, p_curr3->data_);
            location++;
            p_curr3 = p_curr3->next_;
        }
        else if ((p_curr3 == nullptr) && (p_curr4 != nullptr))
        {
            list34.insert(location, p_curr4->data_);
            location++;
            p_curr4 = p_curr4->next_;
        }
    }
}

int main()
{
    List list1;
    //插入
    for (int i = 0; i < 15; i++)
    {
        list1.insert(i, i);
    }
    //删除
    list1.remove(10);
    list1.remove(5);
    //打印
    list1.print();
    list1.reverse();
    list1.print();
    //访问倒数元素
    for (int i = 1; i < 4; i++)
    {
        cout << "倒数第" << i << "个元素是:" << list1.get_reverse_element(i) << endl;
    }
    list1.insert(2, 9999);
    //重载符[]
    for (int i = list1.size_ - 1; i >= 0; i--)
    {
        cout << list1[i] << " ";
    }
    cout << endl;
    List list2;
    list2.insert(0, 10);
    list2.insert(1, 20);
    list2.insert(2, 30);
    list2.print();
    int size2 = list2.size_;
    //合并两个排序链表
    List list3, list4;
    for (int i = 0; i < 5; i++)
    {
        list3.insert(i, 2 * i);
        list4.insert(i, 2 * i + 1);
    }
    list4.insert(5, 12);
    list4.insert(6, 21);
    list3.print();
    list4.print();
    List list34;
    mergeLists(list3, list4, list34);
    list34.print();
    return 1;
}

Guess you like

Origin blog.csdn.net/m0_72734364/article/details/134325567