C++数据结构之--单向链表(SingleList)

单向链表

        单向链表(Singly Linked List)是一种常见的数据结构,它由一系列节点(Node)构成,每个节点包含数据(value)和一个指向下一个节点的指针(next)。每个节点只知道它指向的下一个节点,而无法直接访问前一个节点。

        一个单向链表经常包含一个指向第一个节点的头指针(head),以便能够快速访问到链表的起始位置。链表的最后一个节点的指针通常为空(null),表示链表的结束。

特点

        单向链表的特点:

  1. 单向性:单向链表中的节点只有一个指针,指向下一个节点,而无法直接访问前一个节点。这意味着只能从头开始遍历链表,无法进行反向操作。

  2. 动态性:单向链表的大小可以根据需要动态增长或缩小,因为每个节点的指针可以在运行时被修改。

  3. 灵活性:由于节点之间由指针连接,可以通过调整指针的指向来插入、删除或重新排序节点,而无需移动大量的数据。

  4. 存储效率:相对于数组,单向链表不需要一块连续的内存空间来存储,它可以更灵活地利用内存。但是,由于每个节点需要额外的指针空间,可能会占用更多的内存。

  5. 插入和删除的效率:在链表的开头或结尾插入和删除节点的操作具有较高的效率,只需要修改指针的指向。但是,在链表的中间插入或删除节点需要遍历链表来找到正确的位置,效率较低。

  6. 随机访问的效率:由于无法直接访问前一个节点,要访问链表中的特定节点,需要从头开始遍历链表,直到找到目标节点。因此,链表的随机访问效率相对较低。

实现

数据结构

        节点
class Node {
    public:
    T val;
    Node *next; 
};

        T val:存储节点数据的变量。

        Node *next:指向下一个节点的指针。

        其他
Node *head;
int siz;

        Node *head:头指针

        int siz:链表元素个数

结构图

实现功能

        1、末尾添加元素:void add(T t);

        2、头部添加元素(list第一个位置):void add_first(T t);

        3、指定位置添加元素:void add(int index, T t);

        4、查找元素t:int find(T &t);

        5、获取index位置的元素:T get(int index) ;

        6、删除元素t:void remove(T &t);

        7、翻转list(交换数据):void reverse();

        8、翻转list(重构):void reverse2();

C++实现

        方法声明以及部分实现
/**
 * 单向链表single_list
 */
#ifndef LIST_SINGLE_LIST_H
#define LIST_SINGLE_LIST_H

#include <iostream>

template<typename T>
class SingleList {
public:
    class Node {
    public:
        T val;
        Node *next;
    };

    void add(T t);

    void add_first(T t);

    void add(int index, T t);

    int find(T &t) {// 查找元素t,返回index
        Node *t_h = head->next;
        int i = 0;
        while (t_h != nullptr) {
            if (t_h->val == t) return i;
            t_h = t_h->next;
            i++;
        }
        return -1;
    };

    T get(int index) { // 获取index位置的元素
        Node *t = head->next;
        for (int i = 0; i < index; i++) {
            t = t->next;
        }
        return t->val;
    }

    void remove(T &t) {// 删除元素t
        if (!siz) return;
        Node *t_h = head;
        Node *th_pre;

        while ((th_pre = t_h) != nullptr && t_h->next != nullptr && (t_h = t_h->next)->val != t) {}
        if (t_h->val != t) return; // 如果最后一个节点也不等于t删除失败
        th_pre->next = t_h->next;

        delete t_h;
        t_h = nullptr;
        siz--;
    }

    // 反转 (结构不变交换数据)
    void reverse();

    // 反转(重构)
    void reverse2();

    void print() { // 打印
        Node *t = head->next;
        while (t != nullptr) {
            std::cout << t->val << " ";
            t = t->next;
        }
        std::cout << std::endl;
    }

    SingleList() {
        head = new Node();
    }

private:
    Node *head;
    int siz;
};

#endif //LIST_SINGLE_LIST_H
核心实现
        尾部添加元素
/**
 * 尾部添加元素
 * @brief SingleList::add
 * @param t
 */
template<typename T>
void SingleList<T>::add(T t){ // 尾部添加
    Node *newNode = new Node();
    newNode->val = t;
    Node *t_h = head;
    while (t_h->next != nullptr) {
        t_h = t_h->next;
    }
    t_h->next = newNode;
    siz++;
};
        头部添加元素
/**
 * 头部添加元素
 * @brief SingleList::add_first
 * @param t
 */
template<typename T>
void SingleList<T>::add_first(T t){// 头部添加
    Node *newNode = new Node();
    newNode->val = t;
    newNode->next = head->next;
    head->next = newNode;
    siz++;
};
        指定位置添加元素
/**
 * 在位置index处添加元素
 * @brief SingleList::add
 * @param index
 * @param t
 */
template<typename T>
void SingleList<T>::add(int index, T t){// 指定位置添加
    if (index < 0) return add_first(t);
    if (index > siz - 1) return add(t);

    Node *newNode = new Node();
    newNode->val = t;
    Node *t_h = head->next; // index位置原始节点
    Node *th_pre = head; // index-1位置节点

    for (int i = 0; i < index; i++) {
        th_pre = t_h;
        t_h = t_h->next;
    }
    th_pre->next = newNode;
    newNode->next = t_h;
    siz++;
}
        翻转(交换数据)
// 反转 (结构不变交换数据)
template<typename T>
void SingleList<T>::reverse() {
    if(siz < 2) return;
    int half_siz = siz >> 1;
    Node *t = head;
    for (int i = 0; i < half_siz; i++) {
        t = t->next;
        Node *x = t;
        for (int j = i; j < siz - 1 - i; j++) { // 找到与t对称的节点
            x = x->next;
        }
        // 交换值
        T tp = x->val;
        x->val = t->val;
        t->val = tp;
    }
}
        反转(重构)
template<typename T>
void SingleList<T>::reverse2(){
    if(siz<2) return;

    Node *curr_pre = head->next; // curr_pre始终指向原始数组的第一个元素
    Node *curr = curr_pre == nullptr ? nullptr : curr_pre->next;
    Node *curr_next = curr == nullptr ? nullptr : curr->next;

    // 每次循环将curr放到链表头部,curr_pre->next 指向剩余链表的头部
    while(curr_next != nullptr){
        curr->next = head->next;
        curr_pre->next = curr_next;
        head->next = curr;

        curr = curr_next;
        curr_next = curr_next->next;
    }

    // 最后将末尾元素放到链表首部
    curr->next = head->next;
    curr_pre->next = nullptr;
    head->next = curr;
}

测试

代码

#include "single_list.h"

int main() {
    SingleList<int> singleList = SingleList<int>();
    singleList.add(4);
    singleList.add_first(6);
    singleList.add(1,5);
    singleList.print();

    singleList.reverse();
    singleList.print();

    singleList.add(9);
    singleList.reverse2();
    singleList.print();

    std::cout << singleList.get(1) << std::endl;
    std::cout << singleList.find(4) << std::endl;

    singleList.remove(4);
    singleList.print();

    singleList.remove(10);
    singleList.print();

    singleList.remove(6);
    singleList.print();
}

运行结果

6 5 4 
4 5 6 
9 6 5 4 
6
3
9 6 5 
9 6 5 
9 5 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__XYZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值