终于考完试到家啦,更新开始
上一次实现了Vector,这一次实现List。
List是链表,它有O(1)复杂度的出入删除效率。但是同时它的查找效率却变成了O(n)的复杂度。
有利有弊,这才正常,下面那我们开始实现。
List
目标:
- 链表结构、结点结构的实现
- 迭代器的实现
- 多种构造方法
- 多种操作
这是链表节点的结构,每一个节点有两个 指针分别指向它的前驱和后继结点,data存储我们想要存储的数据,这也是List存在的目的。Node 构造时默认将指向前一个结点的指针和指向后一个结点的指针指向空,这是方便链表的方法调用Node的构造函数增加结点。struct Node { Object data; Node* prev; Node* next; Node(const Object& d = Object{}, Node* p = nullptr, Node* n = nullptr) :data{d}, prev{p}, next{n} { } Node(Object&& d, Node* p = nullptr, Node* n = nullptr) :data{std::move(d)}, prev{p}, next{n} { } };
链表的私有成员包括链表长度、链表的头指针、和链表的尾指针,这是头插和尾插必要的指针。List还包含一个私有成员函数init(),在构造函数中调用,作用是新建一个头结点和一个尾节点,这两个节点不用来存储数据,但他们的存在可以让链表中用来存储数据的元素的地位相同,否则的话,第一个存储结点它将没有前驱结点,却有一个头指针指向它,而其它的结点是头结点指向它,还要特殊处理第一个结点的方法,多麻烦啊。尾节点同理。private: int theSize; Node* head; Node* tail; void init() { theSize = 0; head = new Node; tail = new Node; head -> next = tail; tail -> next = head; }
这是常指针迭代器的的私有成员,包含一个当前迭代器指向的结点的指针。私有成员函数用来返回迭代器指向结点的存储数据,它将在多个方法中被调用。protected: Node* current; Object& retieve() const { return current -> data; } const_iterator(Node* p): current{p} { }
这是迭代器的递增方法,通过查看迭代器指向结点里的指向的下一个指针,实现迭代器的递增。迭代器就像是沿着链条传递,一个接着一个。const_iterator operator++(int) { const_iterator old = *this; ++(*this); return old; }
这是List的核心操作之一insert,可以在任何一个位置插入元素,头插和尾插也不过是,给insert的itr传入默认的头指针和尾指针罢了。他实现的原理是,先将链结打开,再把待插入的元素放到到他们中间,然后把链结接好。iterator insert(iterator itr, const Object& x) { Node* p = itr.current; theSize++; return{p -> prev = p -> prev -> next = new Node{x, p -> prev, p}} }
以上便是List的分析,匆匆写就,纰漏很多,希望多多指教。