穷究链表(十四)

检查stl_list.h,侯捷注释版,可以在侯捷老师的官方网站上面下载得到,之后查看关于list的一部分。L133,定义了list类,L231看到:

1 protected:
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); }

 

移除节点

 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   }

一些构造函数不去管了。

析构函数

1   ~list() {
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   }

 

定义了一个友元函数

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 }

 

因为这个函数内部需要访问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 }

 

这里比较大小并没有声明为其友元,也就是说明其不需要访问内部的私有变量。

清除函数

 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 }

赋值

 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 }

 

合并操作

 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 } 

逆向 

 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 }

 

排序

 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 }

 

其他一些

 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 }

 

从实现上面来看,双向循环链表,带空节点的删除动作比单向链表,不带空节点的删除要简单得多。不过其参数为iterator,而我们之前使用的是pos,还需要遍历过去,还需要判断是否到达正确的位置,如果用类似指针的实现,大概就会差不多。 

 

使用IE6,贴代码一多就慢得不行,使用chrome果然快很多,不过不知道最后显示出来的效果怎么样?

到现在为止,所有的链表内容基本就结束了。下面就是关于链表的面试题收集和解答。谢谢大家来看我的啰嗦,哈哈 

 

posted on 2009-10-22 20:27  cnyao  阅读(306)  评论(0编辑  收藏  举报