C++ 数据结构之-双向链表(link_list)

双向链表

        双向链表(Doubly Linked List)是一种常见的数据结构,它与单向链表相似,但每个节点有两个指针,一个指向前一个节点(前驱节点),一个指向后一个节点(后继节点)。

        双向链表中的每个节点包含三个基本部分:数据域(存储节点的数据)、前驱指针和后继指针。头节点和尾节点是特殊的节点,它们分别代表双向链表的起始和结束。

特点

  1. 双向连接:每个节点都有两个指针,一个指向前驱节点,一个指向后继节点。这种双向连接的结构使得在链表中的节点之间可以进行双向遍历。

  2. 首尾节点:双向链表通常有头节点和尾节点,它们分别代表链表的起始和结束。头节点的前驱指针为空,尾节点的后继指针为空。

  3. 插入和删除的灵活性:相较于单向链表,双向链表可以更方便地在任意位置插入和删除节点。通过调整前驱和后继指针的指向,可以高效地完成这些操作,而无需遍历整个链表。

  4. 前向和后向遍历:由于每个节点都有前驱和后继指针,双向链表可以从头节点或尾节点开始,沿着不同的方向遍历整个链表。这种灵活性在某些情况下能提高效率。

  5. 多占用空间:相对于单向链表,双向链表需要额外存储每个节点的前驱指针,因此会占用更多的内存空间。

  6. 维护复杂性:因为每个节点有两个指针,所以在插入、删除或修改节点时,需要同时更新相关节点的前驱和后继指针,这增加了链表的维护复杂性。

实现

数据结构:

节点:

template<typename T>
class Node {
public:
    T val; // 数据域
    Node *pre; // 前驱节点指针
    Node *next; // 后继节点指针

    ~Node() {
    }
};

 链表属性:

private:
    Node<T> *head; // 头指针
    Node<T> *tail; // 尾指针
    int siz = 0; // 元素个数

 头尾指针使用同一个节点 ,不保存数据

结构图

实现功能

      1、void add(T t);  // 从尾部添加元素

      2、void add(int index, T t); //在索引index处添加元素t

      3、add_first(T t);  // 从头部添加元素

      4、bool contains(T t) const // 判断元素t是否在list中

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

      6、T get_first() ;//获取第一个元素

      7、T get_last(); // 获取最后一个元素

      8、int index_of(T t); 获取指定位置的索引

      9、 void clear();清空list

C++代码

头文件
/**
 * 双向链表实现list
 */
#include <iostream>
#include <bits/functexcept.h>

#ifndef LIST_LINK_LIST_H
#define LIST_LINK_LIST_H

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

    ~Node() {
    }
};

template<typename T>
class LinkList {
public:
    // 从尾部添加元素
    void add(T t);

    // 在索引index处添加元素t
    void add(int index, T t);

    // 从头部添加元素
    void add_first(T t);

    // 清空list
    void clear() {
        Node<T> *t_h = head->next;
        while (t_h != tail) {
            Node<T> * t = t_h;
            t_h = t_h->next;
            delete t;
        }
        siz = 0;
        head->pre = tail->next = nullptr;
    };

    // 判断元素t是否在list中
    bool contains(T t) const {
        Node<T> *t_h = head->next;
        while (t_h != tail) {
            if (t_h->val == t) return true;
            t_h = t_h->next;
        }
        return false;
    };

    T get(int index) {
        if (index < 0 || index > siz - 1) {
            std::__throw_out_of_range_fmt("LinkList<T>::get(int index) index out of range");
        }
        Node<T> *ind_node;
        if (index < (siz >> 1)) {
            ind_node = head->next;
            for (int i = 0; i < index; i++) {
                ind_node = ind_node->next;
            }
        } else {
            ind_node = tail->pre;
            for (int i = siz - 1; i > index; i--) {
                ind_node = ind_node->pre;
            }
        }

        return ind_node->val;
    };

    T get_first() const { return head->next->val; }

    T get_last() const { return tail->pre->val; }

    int index_of(T t);

    int size() const { return siz; }

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

    LinkList() {
        head = tail = new Node<T>();
        head->pre = tail->next = nullptr;
    }

    ~LinkList() {
        Node<T> *t_h = head;
        while (t_h != tail) {
            t_h = t_h->next;
            Node<T> *t = t_h;
            delete t;
        }
    }

private:
    Node<T> *head; // 头指针
    Node<T> *tail; // 尾指针
    int siz = 0; // 元素个数
};

#endif //LIST_LINK_LIST_H
其他实现
末尾添加元素
template<typename T>
void LinkList<T>::add(T t) {
    Node<T> *node = new Node<T>();
    node->val = t;

    if (!siz) {
        head->next = node;
        tail->pre = node;
        node->next = tail;
        node->pre = head;
    } else {
        tail->pre->next = node;
        node->pre = tail->pre;
        tail->pre = node;
        node->next = tail;
    }

    siz++;
}
指定位置添加元素

template<typename T>
void LinkList<T>::add(int index, T t) {
    Node<T> *node = new Node<T>();
    node->val = t;
    Node<T> *ind_node;

    if (index < 0) {
        add_first(t);
    } else if (index >= siz) {
        add(t);
    } else {
        if (index < (siz >> 1)) {
            ind_node = head->next;
            for (int i = 0; i < index; i++) {
                ind_node = ind_node->next;
            }
        } else {
            ind_node = tail->next;
            for (int i = siz - 1; i > index; i--) {
                ind_node = ind_node->pre;
            }
        }
    }
    node->pre = ind_node->pre;
    ind_node->pre->next = node;
    ind_node->pre = node;
    node->next = ind_node;
    siz++;
}
头部添加元素

template<typename T>
void LinkList<T>::add_first(T t) {
    Node<T> *node = new Node<T>();
    node->val = t;

    if (!siz) {
        head->next = node;
        tail->pre = node;
        node->pre = head;
        node->next = tail;
    } else {
        head->next->pre = node;
        node->next = head->next;
        node->pre = head;
        head->next = node;
    }
    siz++;
}
获取指定位置的元素

template<typename T>
int LinkList<T>::index_of(T t) {
    int i = 0;
    Node<T> *t_h = head->next;
    for (i; i < siz; i++) {
        if (t_h->val == t) return i;
        t_h = t_h->next;
    }

    return -1;
}
运行测试
#include "link_list.h"

int main() {
    LinkList<int> linkList = LinkList<int>();
    linkList.add_first(1);
    linkList.add(2);
    linkList.add_first(0);
    linkList.add(0,10);
    linkList.print();

    std::cout << linkList.index_of(1) << std::endl;
    std::cout<< linkList.get(2)<<std::endl;

    std::cout << linkList.contains(2) << std::endl;
    linkList.clear();
    std::cout << "----------" << std::endl;
    linkList.print();
    linkList.add(1);
    linkList.add(2);
    linkList.add(3);
    linkList.print();
}
运行结果
10 0 1 2 
2
1
1
----------
1 2 3 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
c 头插法反转链表是一种将链表进行倒置的方法。具体实现可以参考以下代码: ```c link *reverse(link *head) { link *new_head = NULL; link *temp = NULL; if (head == NULL || head->next == NULL) { return head; } while (head != NULL) { temp = head; //将 temp 从 head 中摘除 head = head->next; //将 temp 插入到 new_head 的头部 temp->next = new_head; new_head = temp; } return new_head; } ``` 这段代码使用了头插法的思路实现链表的反转。通过遍历原链表,每次将头部的节点摘下并插入到新链表的头部,最终得到了一个反转后的链表。你可以将原链表的头节点作为参数传入该函数,函数将返回反转后的链表的头节点。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [字节跳动反转链表--头插法c++](https://blog.csdn.net/weixin_44026260/article/details/108450549)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [反转链表的4种方法c++实现](https://blog.csdn.net/wodazhouyi/article/details/119654297)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

who_am_i__

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

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

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

打赏作者

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

抵扣说明:

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

余额充值