List容器其实就是一个双向链表:一个由节点组成的线性的数据结构,每个节点都存储一个元素,并且包含指向前一个和后一个元素的指针。
这种独特的结构使得它区别于vector拥有一些独特的优缺点:插入/删除效率高——任意位置都为O(1),但是不支持随机访问——无法通过下标访问元素,不需要连续的存储——不需要移动元素,也不涉及扩容复制。
常规操作如push_back,push_front,其原理就是创建一个新节点挂载到尾部的next或者头部的next,pop类似。
而insert/erase则需要通过迭代器获取目标位置,再修改相邻的节点的指针来实现插入和删除,这种方式支持任意位置
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
| #pragma once #include <cstddef> #include <stdexcept>
namespace kiri {
template<typename T> class list { private:
struct Node { T data; Node* prev; Node* next;
Node(const T& val) : data(val), prev(nullptr), next(nullptr) {} };
public:
list() : head_(nullptr), tail_(nullptr), size_(0) {}
~list() { clear(); }
void push_back(const T& val) { Node* node = new Node(val); if (!tail_) { head_ = tail_ = node; } else { tail_->next = node; node->prev = tail_; tail_ = node; } ++size_; }
void push_front(const T& val) { Node* node = new Node(val); if (!head_) { head_ = tail_ = node; } else { node->next = head_; head_->prev = node; head_ = node; } ++size_; }
void pop_back() { if (!tail_) return; Node* to_delete = tail_; tail_ = tail_->prev; if (tail_) tail_->next = nullptr; else head_ = nullptr; delete to_delete; --size_; }
void pop_front() { if (!head_) return; Node* to_delete = head_; head_ = head_->next; if (head_) head_->prev = nullptr; else tail_ = nullptr; delete to_delete; --size_; }
T& front() { if (!head_) throw std::out_of_range("list is empty"); return head_->data; }
T& back() { if (!tail_) throw std::out_of_range("list is empty"); return tail_->data; }
bool empty() const { return size_ == 0; }
std::size_t size() const { return size_; }
void clear() { Node* cur = head_; while (cur) { Node* next = cur->next; delete cur; cur = next; } head_ = tail_ = nullptr; size_ = 0; }
private: Node* head_; Node* tail_; std::size_t size_; };
}
|
实现的功能如下:
| 成员函数 |
功能描述 |
list() |
默认构造函数,初始化一个空链表 |
~list() |
析构函数,释放链表中所有节点 |
push_back() |
在链表尾部插入一个元素 |
push_front() |
在链表头部插入一个元素 |
pop_back() |
移除链表尾部元素 |
pop_front() |
移除链表头部元素 |
front() |
返回头部元素的引用,若链表为空则抛异常 |
back() |
返回尾部元素的引用,若链表为空则抛异常 |
empty() |
判断链表是否为空(即 size == 0) |
size() |
返回当前链表中的元素个数 |
clear() |
清空整个链表,释放所有节点并重置状态 |
运行测试:
