穷究链表(十四)
检查stl_list.h,侯捷注释版,可以在侯捷老师的官方网站上面下载得到,之后查看关于list的一部分。在L133,定义了list类,在L231看到:
1 protected:
2 // 從實作細節看來,本list 只維護一個節點指標,指向最後(尾)節點的下一位置。
3 // 由於這是一個環狀雙向串列,因此,欲對外供應頭節點或尾節點,都十分容易,
4 // 見front(), back()。
5 link_type node; // 永遠指向最後節點的下一節點。該節點無元素值,代表空節點。
6 // 其next 節點永遠是頭節點。
2 // 從實作細節看來,本list 只維護一個節點指標,指向最後(尾)節點的下一位置。
3 // 由於這是一個環狀雙向串列,因此,欲對外供應頭節點或尾節點,都十分容易,
4 // 見front(), back()。
5 link_type node; // 永遠指向最後節點的下一節點。該節點無元素值,代表空節點。
6 // 其next 節點永遠是頭節點。
首先,这个是一个循环双向链表。node为一个没有元素值的空节点,其next节点永远是头节点。
插入节点函数
1 // 在迭代器position 所指位置安插一個節點,內容為x。
2 iterator insert(iterator position, const T& x) {
3 link_type tmp = create_node(x); // 產生一個節點(設妥內容為x)
4 // 調整雙向指標,使tmp 安插進去。
5 tmp->next = position.node;
6 tmp->prev = position.node->prev;
7 (link_type(position.node->prev))->next = tmp;
8 position.node->prev = tmp;
9 return tmp;
10 }
11
12 // 安插一個節點,做為頭節點
13 void push_front(const T& x) { insert(begin(), x); }
14 // 安插一個節點,做為尾節點
15 void push_back(const T& x) { insert(end(), x); }
2 iterator insert(iterator position, const T& x) {
3 link_type tmp = create_node(x); // 產生一個節點(設妥內容為x)
4 // 調整雙向指標,使tmp 安插進去。
5 tmp->next = position.node;
6 tmp->prev = position.node->prev;
7 (link_type(position.node->prev))->next = tmp;
8 position.node->prev = tmp;
9 return tmp;
10 }
11
12 // 安插一個節點,做為頭節點
13 void push_front(const T& x) { insert(begin(), x); }
14 // 安插一個節點,做為尾節點
15 void push_back(const T& x) { insert(end(), x); }
移除节点
1 // 移除迭代器position 所指節點
2 iterator erase(iterator position) {
3 link_type next_node = link_type(position.node->next);
4 link_type prev_node = link_type(position.node->prev);
5 prev_node->next = next_node;
6 next_node->prev = prev_node;
7 destroy_node(position.node);
8 return iterator(next_node);
9 }
10
11 // 移除頭節點
12 void pop_front() { erase(begin()); }
13 // 移除尾節點
14 void pop_back() {
15 iterator tmp = end();
16 erase(--tmp);
17 }
2 iterator erase(iterator position) {
3 link_type next_node = link_type(position.node->next);
4 link_type prev_node = link_type(position.node->prev);
5 prev_node->next = next_node;
6 next_node->prev = prev_node;
7 destroy_node(position.node);
8 return iterator(next_node);
9 }
10
11 // 移除頭節點
12 void pop_front() { erase(begin()); }
13 // 移除尾節點
14 void pop_back() {
15 iterator tmp = end();
16 erase(--tmp);
17 }
一些构造函数不去管了。
析构函数
1 ~list() {
2 clear();
3 put_node(node);
4 }
2 clear();
3 put_node(node);
4 }
移动
1 // 將[first,last) 內的所有元素搬移到position 處。
2 void transfer(iterator position, iterator first, iterator last) {
3 if (position != last) {
4 (*(link_type((*last.node).prev))).next = position.node; // (1)
5 (*(link_type((*first.node).prev))).next = last.node; // (2)
6 (*(link_type((*position.node).prev))).next = first.node; // (3)
7 link_type tmp = link_type((*position.node).prev); // (4)
8 (*position.node).prev = (*last.node).prev; // (5)
9 (*last.node).prev = (*first.node).prev; // (6)
10 (*first.node).prev = tmp; // (7)
11 }
12 }
2 void transfer(iterator position, iterator first, iterator last) {
3 if (position != last) {
4 (*(link_type((*last.node).prev))).next = position.node; // (1)
5 (*(link_type((*first.node).prev))).next = last.node; // (2)
6 (*(link_type((*position.node).prev))).next = first.node; // (3)
7 link_type tmp = link_type((*position.node).prev); // (4)
8 (*position.node).prev = (*last.node).prev; // (5)
9 (*last.node).prev = (*first.node).prev; // (6)
10 (*first.node).prev = tmp; // (7)
11 }
12 }
定义了一个友元函数
friend bool operator== __STL_NULL_TMPL_ARGS (const list& x, const list& y);
其实现如下
1 template <class T, class Alloc>
2 inline bool operator==(const list<T,Alloc>& x, const list<T,Alloc>& y)
3 {
4 typedef typename list<T,Alloc>::link_type link_type;
5 link_type e1 = x.node;
6 link_type e2 = y.node;
7 link_type n1 = (link_type) e1->next;
8 link_type n2 = (link_type) e2->next;
9 for ( ; n1 != e1 && n2 != e2 ;
10 n1 = (link_type) n1->next, n2 = (link_type) n2->next)
11 if (n1->data != n2->data)
12 return false;
13 return n1 == e1 && n2 == e2;
14 }
2 inline bool operator==(const list<T,Alloc>& x, const list<T,Alloc>& y)
3 {
4 typedef typename list<T,Alloc>::link_type link_type;
5 link_type e1 = x.node;
6 link_type e2 = y.node;
7 link_type n1 = (link_type) e1->next;
8 link_type n2 = (link_type) e2->next;
9 for ( ; n1 != e1 && n2 != e2 ;
10 n1 = (link_type) n1->next, n2 = (link_type) n2->next)
11 if (n1->data != n2->data)
12 return false;
13 return n1 == e1 && n2 == e2;
14 }
因为这个函数内部需要访问node成员变量,所以需要声明为友元才行。
还有一个比较大小的函数
1 template <class T, class Alloc>
2 inline bool operator<(const list<T, Alloc>& x, const list<T, Alloc>& y) {
3 return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
4 }
2 inline bool operator<(const list<T, Alloc>& x, const list<T, Alloc>& y) {
3 return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
4 }
这里比较大小并没有声明为其友元,也就是说明其不需要访问内部的私有变量。
清除函数
1 // 清除所有節點(整個串列)
2 template <class T, class Alloc>
3 void list<T, Alloc>::clear()
4 {
5 link_type cur = (link_type) node->next; // begin()
6 while (cur != node) { // 巡訪每一個節點
7 link_type tmp = cur;
8 cur = (link_type) cur->next;
9 destroy_node(tmp); // 摧毀(解構並釋放)一個節點
10 }
11 // 恢復node 原始狀態
12 node->next = node;
13 node->prev = node;
14 }
2 template <class T, class Alloc>
3 void list<T, Alloc>::clear()
4 {
5 link_type cur = (link_type) node->next; // begin()
6 while (cur != node) { // 巡訪每一個節點
7 link_type tmp = cur;
8 cur = (link_type) cur->next;
9 destroy_node(tmp); // 摧毀(解構並釋放)一個節點
10 }
11 // 恢復node 原始狀態
12 node->next = node;
13 node->prev = node;
14 }
赋值
1 template <class T, class Alloc>
2 list<T, Alloc>& list<T, Alloc>::operator=(const list<T, Alloc>& x) {
3 if (this != &x) {
4 iterator first1 = begin();
5 iterator last1 = end();
6 const_iterator first2 = x.begin();
7 const_iterator last2 = x.end();
8 while (first1 != last1 && first2 != last2) *first1++ = *first2++;
9 if (first2 == last2)
10 erase(first1, last1);
11 else
12 insert(last1, first2, last2);
13 }
14 return *this;
15 }
2 list<T, Alloc>& list<T, Alloc>::operator=(const list<T, Alloc>& x) {
3 if (this != &x) {
4 iterator first1 = begin();
5 iterator last1 = end();
6 const_iterator first2 = x.begin();
7 const_iterator last2 = x.end();
8 while (first1 != last1 && first2 != last2) *first1++ = *first2++;
9 if (first2 == last2)
10 erase(first1, last1);
11 else
12 insert(last1, first2, last2);
13 }
14 return *this;
15 }
合并操作
1 // 將x 合併到*this 身上。兩個lists 的內容都必須先經過遞增排序。
2 template <class T, class Alloc>
3 void list<T, Alloc>::merge(list<T, Alloc>& x) {
4 iterator first1 = begin();
5 iterator last1 = end();
6 iterator first2 = x.begin();
7 iterator last2 = x.end();
8
9 // 注意:前提是,兩個lists 都已經過遞增排序,
10 while (first1 != last1 && first2 != last2)
11 if (*first2 < *first1) {
12 iterator next = first2;
13 transfer(first1, first2, ++next);
14 first2 = next;
15 }
16 else
17 ++first1;
18 if (first2 != last2) transfer(last1, first2, last2);
19 }
2 template <class T, class Alloc>
3 void list<T, Alloc>::merge(list<T, Alloc>& x) {
4 iterator first1 = begin();
5 iterator last1 = end();
6 iterator first2 = x.begin();
7 iterator last2 = x.end();
8
9 // 注意:前提是,兩個lists 都已經過遞增排序,
10 while (first1 != last1 && first2 != last2)
11 if (*first2 < *first1) {
12 iterator next = first2;
13 transfer(first1, first2, ++next);
14 first2 = next;
15 }
16 else
17 ++first1;
18 if (first2 != last2) transfer(last1, first2, last2);
19 }
逆向
1 // 將*this 的內容逆向重置
2 template <class T, class Alloc>
3 void list<T, Alloc>::reverse() {
4 // 以下判斷,如果是空白串列,或僅有一個元素,就不做任何動作。
5 // 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。
6 if (node->next == node || link_type(node->next)->next == node) return;
7 iterator first = begin();
8 ++first;
9 while (first != end()) {
10 iterator old = first;
11 ++first;
12 transfer(begin(), old, first);
13 }
14 }
2 template <class T, class Alloc>
3 void list<T, Alloc>::reverse() {
4 // 以下判斷,如果是空白串列,或僅有一個元素,就不做任何動作。
5 // 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。
6 if (node->next == node || link_type(node->next)->next == node) return;
7 iterator first = begin();
8 ++first;
9 while (first != end()) {
10 iterator old = first;
11 ++first;
12 transfer(begin(), old, first);
13 }
14 }
排序
1 // list 不能使用STL 演算法sort(),必須使用自己的sort() member function,
2 // 因為STL演算法sort() 只接受RamdonAccessIterator.
3 // 本函式採用quick sort.
4 template <class T, class Alloc>
5 void list<T, Alloc>::sort() {
6 // 以下判斷,如果是空白串列,或僅有一個元素,就不做任何動作。
7 // 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。
8 if (node->next == node || link_type(node->next)->next == node) return;
9
10 // 一些新的lists,做為中介資料存放區
11 list<T, Alloc> carry;
12 list<T, Alloc> counter[64];
13 int fill = 0;
14 while (!empty()) {
15 carry.splice(carry.begin(), *this, begin());
16 int i = 0;
17 while(i < fill && !counter[i].empty()) {
18 counter[i].merge(carry);
19 carry.swap(counter[i++]);
20 }
21 carry.swap(counter[i]);
22 if (i == fill) ++fill;
23 }
24
25 for (int i = 1; i < fill; ++i)
26 counter[i].merge(counter[i-1]);
27 swap(counter[fill-1]);
28 }
2 // 因為STL演算法sort() 只接受RamdonAccessIterator.
3 // 本函式採用quick sort.
4 template <class T, class Alloc>
5 void list<T, Alloc>::sort() {
6 // 以下判斷,如果是空白串列,或僅有一個元素,就不做任何動作。
7 // 使用size() == 0 || size() == 1 來判斷,雖然也可以,但是比較慢。
8 if (node->next == node || link_type(node->next)->next == node) return;
9
10 // 一些新的lists,做為中介資料存放區
11 list<T, Alloc> carry;
12 list<T, Alloc> counter[64];
13 int fill = 0;
14 while (!empty()) {
15 carry.splice(carry.begin(), *this, begin());
16 int i = 0;
17 while(i < fill && !counter[i].empty()) {
18 counter[i].merge(carry);
19 carry.swap(counter[i++]);
20 }
21 carry.swap(counter[i]);
22 if (i == fill) ++fill;
23 }
24
25 for (int i = 1; i < fill; ++i)
26 counter[i].merge(counter[i-1]);
27 swap(counter[fill-1]);
28 }
其他一些
1 template <class T, class Alloc> template <class BinaryPredicate>
2 void list<T, Alloc>::unique(BinaryPredicate binary_pred) {
3 iterator first = begin();
4 iterator last = end();
5 if (first == last) return;
6 iterator next = first;
7 while (++next != last) {
8 if (binary_pred(*first, *next))
9 erase(next);
10 else
11 first = next;
12 next = first;
13 }
14 }
15
16 template <class T, class Alloc> template <class StrictWeakOrdering>
17 void list<T, Alloc>::merge(list<T, Alloc>& x, StrictWeakOrdering comp)
18 {
19 iterator first1 = begin();
20 iterator last1 = end();
21 iterator first2 = x.begin();
22 iterator last2 = x.end();
23 while (first1 != last1 && first2 != last2)
24 if (comp(*first2, *first1)) {
25 iterator next = first2;
26 transfer(first1, first2, ++next);
27 first2 = next;
28 }
29 else
30 ++first1;
31 if (first2 != last2) transfer(last1, first2, last2);
32 }
33
34 template <class T, class Alloc> template <class StrictWeakOrdering>
35 void list<T, Alloc>::sort(StrictWeakOrdering comp) {
36 if (node->next == node || link_type(node->next)->next == node) return;
37 list<T, Alloc> carry;
38 list<T, Alloc> counter[64];
39 int fill = 0;
40 while (!empty()) {
41 carry.splice(carry.begin(), *this, begin());
42 int i = 0;
43 while(i < fill && !counter[i].empty()) {
44 counter[i].merge(carry, comp);
45 carry.swap(counter[i++]);
46 }
47 carry.swap(counter[i]);
48 if (i == fill) ++fill;
49 }
50
51 for (int i = 1; i < fill; ++i) counter[i].merge(counter[i-1], comp);
52 swap(counter[fill-1]);
53 }
2 void list<T, Alloc>::unique(BinaryPredicate binary_pred) {
3 iterator first = begin();
4 iterator last = end();
5 if (first == last) return;
6 iterator next = first;
7 while (++next != last) {
8 if (binary_pred(*first, *next))
9 erase(next);
10 else
11 first = next;
12 next = first;
13 }
14 }
15
16 template <class T, class Alloc> template <class StrictWeakOrdering>
17 void list<T, Alloc>::merge(list<T, Alloc>& x, StrictWeakOrdering comp)
18 {
19 iterator first1 = begin();
20 iterator last1 = end();
21 iterator first2 = x.begin();
22 iterator last2 = x.end();
23 while (first1 != last1 && first2 != last2)
24 if (comp(*first2, *first1)) {
25 iterator next = first2;
26 transfer(first1, first2, ++next);
27 first2 = next;
28 }
29 else
30 ++first1;
31 if (first2 != last2) transfer(last1, first2, last2);
32 }
33
34 template <class T, class Alloc> template <class StrictWeakOrdering>
35 void list<T, Alloc>::sort(StrictWeakOrdering comp) {
36 if (node->next == node || link_type(node->next)->next == node) return;
37 list<T, Alloc> carry;
38 list<T, Alloc> counter[64];
39 int fill = 0;
40 while (!empty()) {
41 carry.splice(carry.begin(), *this, begin());
42 int i = 0;
43 while(i < fill && !counter[i].empty()) {
44 counter[i].merge(carry, comp);
45 carry.swap(counter[i++]);
46 }
47 carry.swap(counter[i]);
48 if (i == fill) ++fill;
49 }
50
51 for (int i = 1; i < fill; ++i) counter[i].merge(counter[i-1], comp);
52 swap(counter[fill-1]);
53 }
从实现上面来看,双向循环链表,带空节点的删除动作比单向链表,不带空节点的删除要简单得多。不过其参数为iterator,而我们之前使用的是pos,还需要遍历过去,还需要判断是否到达正确的位置,如果用类似指针的实现,大概就会差不多。
使用IE6,贴代码一多就慢得不行,使用chrome果然快很多,不过不知道最后显示出来的效果怎么样?
到现在为止,所有的链表内容基本就结束了。下面就是关于链表的面试题收集和解答。谢谢大家来看我的啰嗦,哈哈