C++ 数据结构——链表(一)

 单链表

其实可以简单的理解为数组,但只要用的好,实际功能是远远大于数组的,再此次文章中,我们暂且可以简单理解为数组,但不要被误导,两者实际上还有很多的不同(比如说数组的随机访问时间复杂度为O(1)而单链表为O(n)等等等等)

举个简单的链表

list = [ 1, 2, 3, 4, 5]  // 我们可以将其画出来,就像这样

1 -> 2 -> 3 -> 4 -> 5 //这里的每个数组就是链表的节点并通过 " -> " 串在了一起

意思也就是说,我们只要能将一些零零散散的节点像烤串一样串在一起,那么就是实现了一个简单的链表

算法逻辑

第一步(节点)

节点中需要存放数据,并且要利用指针访问

class Node 
{
public:
    int data;
    Node* next;
};

第二步(连接链表)

链表的链接与节点数据的存放是辩证统一的,两者缺一不可。

一个最基础的链表,至少具有插入元素和输出元素的功能,不过在此我也会实现链表的一些其他功能(随机访问,随机插入,排序等等等等)

链表功能

插入节点

表尾插入

意思就是说,我们将从头开始遍历链表(链表头号元素不为空的时候),持续遍历到不存在下一个节点为止,当程序发现不存在下一个节点时,在此处插入新的节点

void insert(int data) 
{
    Node* new_node = new Node();
    new_node->data = data;
    new_node->next = nullptr;

    if (head == nullptr) 
    {
        head = new_node;
    }
    else {
        Node* current = head;
        while (current->next != nullptr) 
        {
            current = current->next;
        }
        current->next = new_node;
    }
}

随机插入

和上述方法类似,也会从头开始遍历链表,但不会一直遍历到表尾(除非插入位置的值大于链表的长度),当遍历链表直至num的位置时插入新的节点

num = 我们需要插入元素的位置,并在此位置的左侧插入新的节点

void rand_insert(int num, int data) 
{
    Node* new_node = new Node();
    new_node->data = data;
    new_node->next = nullptr;

    if (head == nullptr) 
    {
        head = new_node;
    }
    else 
    {
        Node* current = head;
        int count = 0;
        while (current->next != nullptr && count < num) 
        {
            current = current->next;
            count++;
        }
        if (current->next != nullptr) 
        {
            new_node->next = current->next;
            current->next = new_node;
        }
        else {
            current->next = new_node;
        }
    }
}

这里着重说明一些核心代码
new_node->next = current->next

这一行将新节点的下一个节点指向当前节点的下一个节点。这样做的目的是在当前节点和它的下一个节点之间插入新节点,使得新节点成为当前节点的下一个节点。

current->next = new_node

这一行将当前节点的下一个节点更新为新节点。这样,新节点就被正确地插入到了链表中

输出链表

或许看到这里你也已经明白怎么输出链表了,还是跟上述插入节点一样,从表头开始遍历链表,每遍历完一个节点就输出这个节点的值即可

void display() 
{
    if (head == nullptr) 
    {
        return;
    }
    else 
    {
        Node* current = head;
        while (current->next != nullptr) 
        {
            cout << current->data << "->";
            current = current->next;
        }
        cout << current->data << endl;
    }
}

删除节点

有链表的插入那么也就有节点的删除,这里将通过访问链表中节点的位置来删除节点,就跟数组类似,访问到目标节点时停止遍历,使指向该节点的指针指向下一个节点,从而“跳过”此节点直接访问下一个节点

void delete_node(int num)
{
    if (head == nullptr) 
    {
        return;
    }
    else 
    {
        if (num == 0)
        {
            Node* temp = head;
            head = head->next;
            delete temp;
            return;
        }
        Node* current = head;
        int count = 0;
        while (count < num - 1) 
        {
            current = current->next;
            count++;
        }
        Node* temp = current->next;
        current->next = current->next->next;
        delete temp;
    }
}

返回链表长度

无需多元,从头开始遍历,设定一个计数器count使每遍历完一个节点进行count += 1 的操作,最后返回的count的值即为链表的长度

int len() 
{
    if (head == nullptr) 
    {
        return 0;
    }
    else 
    {
        Node* current = head;
        int count = 1;
        while (current->next != nullptr) 
        {
            current = current->next;
            count++;
        }
        return count;
    }
}

随机访问

位置访问

跟数组一样,在下表上写上链表中元素的位置,程序就会给你返回此位置元素的值,原理还是跟上述方法一样,从头开始遍历,直至遍历到num时停止并返回此时遍历到的元素的值即可

num = 需要访问的元素的位置

int value(int num) 
{
    if (head == nullptr) 
    {
        return -1;
    }
    else 
    {
        Node* current = head;
        int count = 0;
        while (count < num) 
        {
            current = current->next;
            count++;
        }
        return current->data;
    }
}

查找元素

给定一个数,查看链表中是否有这个数。

一般情况下我们可以通过遍历链表来实现,这是最无脑且有效的办法,但如果题目中有一些特殊情况,比如已排序的链表之类的话,那么我们可以用二分查找等方式降低程序的时间复杂的

不过遍历链表查找元素的时间复杂度也不高,为O(n)

num = 我们要查找的元素的值

 void get(int num)
 {
     if (head == nullptr) 
     {
         return;
     }
     else 
     {
         for (int i = 0; i < len(); i++)
         {
             if (value(i) == num) 
             {
                 cout << "找到元素" << num << ",其位置为" << i << endl;
                 return;
             }
         }
         cout << "链表中不存在该元素" << endl;
     }
 }

链表的排序

就跟数组的排序一样,根据链表中节点的值或者一些其他要求进行排序,这里以冒泡排序为例,不过冒泡排序是一个时间复杂度相对较高O(n**2)的排序方式,也是最简单通俗易懂的排序方式,在此不会多讲,博主会在下一期文章中专门讲11中不同的排序方式。

链表排序的底层逻辑就是节点内数据的交换,至于怎么交换,那么就取决于使用了什么样的排序方式了

void bubble_sort() 
{
    if (head == nullptr) 
    {
        return;
    }
    else 
    {
        bool swapped = true;
        while (swapped) 
        {
            swapped = false;
            Node* current = head;
            while (current->next != nullptr)
            {
                if (current->data > current->next->data) 
                {
                    swap(current->data, current->next->data);
                    swapped = true;
                }
                current = current->next;
            }
        }
    }
}

完整代码

#include <iostream>
using namespace std;

class Node 
{
public:
    int data;
    Node* next;
};

class LinkedList 
{
public:
    Node* head;
    LinkedList() : head(nullptr) {}

    void insert(int data) 
    {
        Node* new_node = new Node();
        new_node->data = data;
        new_node->next = nullptr;

        if (head == nullptr) 
        {
            head = new_node;
        }
        else {
            Node* current = head;
            while (current->next != nullptr) 
            {
                current = current->next;
            }
            current->next = new_node;
        }
    }

    void display() 
    {
        if (head == nullptr) 
        {
            return;
        }
        else 
        {
            Node* current = head;
            while (current->next != nullptr) 
            {
                cout << current->data << "->";
                current = current->next;
            }
            cout << current->data << endl;
        }
    }

    int len() 
    {
        if (head == nullptr) 
        {
            return 0;
        }
        else 
        {
            Node* current = head;
            int count = 1;
            while (current->next != nullptr) 
            {
                current = current->next;
                count++;
            }
            return count;
        }
    }

    int value(int num) 
    {
        if (head == nullptr) 
        {
            return -1;
        }
        else 
        {
            Node* current = head;
            int count = 0;
            while (count < num) 
            {
                current = current->next;
                count++;
            }
            return current->data;
        }
    }

    void rand_insert(int num, int data) 
    {
        Node* new_node = new Node();
        new_node->data = data;
        new_node->next = nullptr;

        if (head == nullptr) 
        {
            head = new_node;
        }
        else 
        {
            Node* current = head;
            int count = 0;
            while (current->next != nullptr && count < num) 
            {
                current = current->next;
                count++;
            }
            if (current->next != nullptr) 
            {
                new_node->next = current->next;
                current->next = new_node;
            }
            else {
                current->next = new_node;
            }
        }
    }

    void get(int num)
    {
        if (head == nullptr) 
        {
            return;
        }
        else 
        {
            for (int i = 0; i < len(); i++)
            {
                if (value(i) == num) 
                {
                    cout << "找到元素" << num << ",其位置为" << i << endl;
                    return;
                }
            }
            cout << "链表中不存在该元素" << endl;
        }
    }

    void delete_node(int num)
    {
        if (head == nullptr) 
        {
            return;
        }
        else 
        {
            if (num == 0)
            {
                Node* temp = head;
                head = head->next;
                delete temp;
                return;
            }
            Node* current = head;
            int count = 0;
            while (count < num - 1) 
            {
                current = current->next;
                count++;
            }
            Node* temp = current->next;
            current->next = current->next->next;
            delete temp;
        }
    }

    void bubble_sort() 
    {
        if (head == nullptr) 
        {
            return;
        }
        else 
        {
            bool swapped = true;
            while (swapped) 
            {
                swapped = false;
                Node* current = head;
                while (current->next != nullptr)
                {
                    if (current->data > current->next->data) 
                    {
                        swap(current->data, current->next->data);
                        swapped = true;
                    }
                    current = current->next;
                }
            }
        }
    }
};

int main() 
{
    LinkedList list;
    list.insert(5);
    list.insert(4);
    list.insert(3);
    list.insert(2);
    list.insert(1);
    cout << "链表初始化为:" << endl;
    list.display();
    int num = 4;
    list.delete_node(num);
    cout << "删除第" << num + 1 << "节点后" << endl;
    list.display();
    cout << "长度为:" << list.len() << endl;
    cout << "此位置元素值为:" << list.value(1) << endl;
    list.get(2);
    list.display();
    list.rand_insert(1, 9999); //在左侧插入
    list.display();
    list.bubble_sort();
    cout << "排序后的链表为:" << endl;
    list.display();
    return 0;
}

这就是本期文章的全部内容了,希望对你有帮助,在评论区留下自己的观点给博主提提建议。

当然,最重要的是,自己试试看吧,你会做的更好

  • 19
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值