数据结构小记【Python/C++版】——链表篇

一,基础概念

链表是一种线性表结构,节点是链表中的基本单元。

链表是节点的集合,节点可以分布在内存中的任何位置,每个节点都存储着链表中下一个节点的地址。

如图,看似随意摆放的各个节点,其内部其实有链表维持的相对位置信息。

我们用"指针"来表示链表中的方向,为了维持节点之间的先后顺序,链表给每个节点都附加了一个指针。单链表中的每个节点都包含指向后一个节点的后向指针,双链表中的每个节点不仅包含指向后一个节点的后向指针,也包含指向前一个节点的前向指针。链表在内存上不一定是连续分布的,我们只能沿着指针的方向迭代遍历链表上的节点,无法直接根据下标来访问链表指定位置上的元素。

链表和数组相比,主要优势:

1.链表在编译期不需要知道具体大小。

2.数组中的元素在内存中是连续分布的,且以相同距离间隔开。因此,往数组中插入新的元素就需要移动数组中的其他数据,链表不需要这么麻烦。

数组的内存分布:

链表的内存分布:

二,链表的图示结构

不包含头节点和尾节点的链表:

包含头节点和尾节点的链表:

三,节点的代码表示

以单链表为例,节点的组成:

1,数据域:节点的元素值

2,指针域:指向下一个节点的指针

Python实现:

python 复制代码
class Node:
    def __init__(self, value):
        self.data = value
        self.next = None

C++实现:

cpp 复制代码
struct Node {
        int value;   //节点的元素值,假设存储的元素是int类型
        Node *next;  //后向指针
        Node(int val = 0) { value = val; next = NULL; } //构造函数
       };

如果要实现双链表,且用泛型来表示元素值的类型,可以这样实现节点:

cpp 复制代码
template <typename T>
struct Node {
        T value;     //节点的元素值
        Node *next;  //后向指针
        Node *prev;  //前向指针
        Node() { next = NULL; prev = NULL; }   //默认构造函数
        Node(const T &val) { value = val; next = NULL; prev = NULL; } //初始化元素值的构造函数
      };

四,链表常见操作

1.初始化和使用链表

Python实现:

python 复制代码
class Node:
    def __init__(self, item):
        self.item = item
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None

if __name__ == '__main__':
    linkedList = LinkedList()

    linkedList.head = Node(1)
    second = Node(2)
    third = Node(3)

    #连接各个节点
    linkedList.head.next = second
    second.next = third

    while linkedList.head != None:
        print(linkedList.head.item, end=" ")
        linkedList.head = linkedList.head.next

C++实现:

cpp 复制代码
#include <iostream>
using namespace std;

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

int main() {
    Node* head;
    Node* one = NULL;
    Node* two = NULL;
    Node* three = NULL;

    one = new Node();
    two = new Node();
    three = new Node();

    one->value = 1;
    two->value = 2;
    three->value = 3;

    //连接各个节点
    one->next = two;
    two->next = three;
    three->next = NULL;

    head = one;
    while (head != NULL) {
        cout << head->value << endl;
        head = head->next;
    }
}

2.链表往后追加节点

Python实现:

python 复制代码
def append(self, new_element):
    current = self.head
    if self.head:
        while current.next:
            current = current.next
        current.next = new_element
    else:
        self.head = new_element

C++实现:

cpp 复制代码
class Node
{
public:
    int data;
    Node* next;
};

void append(Node** head_ref, int new_data)
{
    Node* new_node = new Node();
    Node* last = *head_ref;
    new_node->data = new_data;
    new_node->next = NULL;
    if (*head_ref == NULL)
    {
        *head_ref = new_node;
        return;
    }
    while (last->next != NULL)
    {
        last = last->next;
    }
    last->next = new_node;
    return;
}

3.链表指定位置添加节点

Python实现:

python 复制代码
def insert(self, new_element, position):
    counter = 1
    current = self.head
    if position > 1:
        while current and counter < position:
           if counter == position - 1:
                new_element.next = current.next
                current.next = new_element
           current = current.next
           counter += 1
    elif position == 1 :
           new_element.next = self.head
           self.head = new_element

C++实现:

cpp 复制代码
class Node
{
    public:
    int data;
    Node *next;
};

void insert(Node* prev_node, int new_data)
{
    if (prev_node == NULL) {
        cout << "The given previous node cannot be NULL";
        return;
    }
    Node* new_node = new Node();
    new_node->data = new_data;
    //最核心的两步
    new_node->next = prev_node->next;
    prev_node->next = new_node;
}

4.获得链表长度

Python实现:

python 复制代码
def getlength(self):
    current = self.head
    count = 0
    while current.next:
        count = count + 1
        current = current.next
    return count

C++实现:

cpp 复制代码
int getlength(Node* head)
{
    int count = 0;
    Node* current = head;
    while (current != NULL) {
        count++;
        current = current->next;
    }
    return count;
}

5.删除指定节点

具体操作: 将前一个节点的next指针指向被删除节点的下一个节点

Python实现:

示意图:

python 复制代码
def delete(self, value):
    current = self.head
    previous = None
    while current.value != value and current.next:
        previous = current
        current = current.next
    if current.value == value:
        if previous:
            previous.next = current.next
        else:
            self.head = current.next

C++实现:

cpp 复制代码
typedef struct Node {
    int data;
    struct Node* next;
} Node;

void delete(Node** head, int position)
{
    Node* temp;
    Node* prev;
    temp = *head;
    prev = *head;
    for (int i = 0; i < position; i++) {
        if (i == 0 && position == 1) {
            *head = (*head)->next;
            free(temp);
        }
        else {
            if (i == position - 1 && temp) {
                prev->next = temp->next;
                free(temp);
            }
            else {
                prev = temp;
                if (prev == NULL)
                    break;
                temp = temp->next;
            }
        }
    }
}

6.查询某节点是否存在

Python实现:

python 复制代码
def search(self, item):
    current = self.head
    found = False
    while current != None and not found:
        if current.value == item:
            found = True
        else:
            current = current.next()
    return found

C++实现:

cpp 复制代码
class Node {
public:
    int data;
    Node* next;
};


bool search(Node* head, int x)
{
    Node* current = head;
    while (current != NULL) {
        if (current->data == x)
            return true;
        current = current->next;
    }
    return false;
}

五,链表的主要使用场景

如果应用场景包含很多查询操作,此时更适合使用数组。如果应用场景中,需要使用的元素个数不确定,且需要经常对元素进行添加和删除操作,此时使用链表结构会更合适。简单概括就是,链表适合使用在频繁增删的场景,数组适合使用在频繁查询的场景。

六,参考阅读

《Problem Solving with Algorithms and Data Structures Using Python, Second Edition》
https://www.programiz.com/dsa/linked-list
https://www.geeksforgeeks.org/what-is-linked-list/?ref=lbp
https://gist.github.com/bavly/ef45e5b9db7d9a400b51ec132f553a0a
https://pumpkinprogrammerdotcom4.wordpress.com/2014/06/13/c-tutorial-intro-to-linked-lists/

相关推荐
小虎牙^O^1 分钟前
棋盘格隐写:基于奇偶相位的双图隐藏与还原
图像处理·python·安全
开开心心就好1 分钟前
文件关联被破坏怎么修?免费工具一键修复
java·服务器·开发语言·pdf·ocr·启发式算法·宽度优先
不停喝水2 分钟前
【前端转全栈java速通课】 项目实战④12-14节 拦截器过滤器和全局配置-cors跨域设置-token体系-利用session做验证码
java·开发语言·前端·ai·容器
小白鸽i2 分钟前
【linux】麒麟桌面版安装人大金仓V8
linux·运维
Ruiery7 分钟前
Linux 6.6内核内存管理深度解析(三):页表与缺页处理 — 虚拟地址怎么按需映射到物理页
linux·运维·服务器
薛定猫AI7 分钟前
【技术干货】基于本地优先架构的开源AI智能体Octopus系统设计与实战解析
python·机器学习·ai·大模型·技术实战
ouynagda8 分钟前
iMX6ull Linux 嵌入式驱动开发笔记(LCD / ADXL345 / SPI 子系统)
linux·arm开发·驱动开发·笔记·嵌入式硬件
小诗懂技术8 分钟前
linux驱动中断,相关中断的方式与适用场景
linux·arm开发·驱动开发·算法
CVer儿10 分钟前
起源引擎harmmer++ 配置
开发语言
xiaoqiMikko13 分钟前
Linux 实战(九·完):重定向、sudo、通配符的坑 + 报错速查表 —— 三台真机实测
linux·centos