STL学习笔记-- list

list 双向链表容器(双向循环链表的数据结构)

    list 是双向链表的一个泛化容器的容器,实现了 Reversible Container 、 Front Insertion Sequence 和 Back Insertion Sequence 等概念的接口规范。作为一种序列容器,它的数据元素可通过链表指针串接成逻辑上的线性表。
    不同于采用线性表顺序存储结构的 vector 和 deque 容器,list 双向链表中任一位置的元素查找、插入和删除,都具有高效的常数阶算法时间复杂度 O(1).
    list 双向链表容器的 C++ 标准头文件为 list ,必须通过宏语句 "#include <list>" 包含进来,才能对 list 双向链表容器进行开发。

创建 list 对象
为了管理双向链表的元素数据,必须先用 list 容器的构造函数,创建一个 list 对象。
1.    list()
    创建一个没有任何元素的 list 对象。此构造函数是 list(const A& a = A()) 的一个默认调用方式,其中 A 为内存分配器。
    如下一行代码创建了一个空的 list 对象 lInt
    list<int>  lInt;

2.    list(size_type n)
    创建一个链接有 n 个元素的 list 对象,每个元素采用它的类型下的默认值。
    例如,下面一行代码创建了具有 10 个元素的 list 对象 lInt ,每个元素初始值为 0 。
    list<int>  lInt;

3.    list(size_type, const T& value)
    创建一个有 n 个元素的 list 对象,这些元素的初始值均为 value ,
    例如,下面一行代码创建了一个具有 10 个元素的 list 对象 lDou ,每个元素的初始值为 1.111 ;
    list<double>  lDou(10, 1.111);

4.    list(const list&)
    list拷贝构造函数,通过拷贝一个 list 对象的元素,创建一个新的 list 对象。此时,新旧 list 容器的元素对应相等。
    例如,下面使用 list 对象 lChr1 , 创建另一个 list 对象 lChr2 ,lChr1 对象的 5 个元素也具有字符值 "K"
    list<char>  lChr1(5, 'K');
    list<char>  lChr2(lChr1);

5.    list(InputIterator first, InputIterator last)
    将另一个 list 对象的迭代器区间 [first, last) 所指的元素,拷贝到新创建的 list 对象中。它是更完整的 list(const InputIterator first, const InputIterator last, const A& a=A())构造函数的一个省略写法。
    例如,下面代码将数组 iArray 的 3 个整数插入链表中,创建 list 对象 l
    int iArray[] = {19, 13, 38};



初始化赋值
利用 list 提供的 push_back() 函数,可将元素依次链入链表中。 push_back() 函数常用于 list 容器的初始化。



元素的遍历
由于链表中的数据需要一个个元素进行遍历,因此, list 元素的遍历中有使用迭代器的方式进行。


用迭代器遍历 list 元素
 1 -------------------------------------------------------- 用迭代器遍历 list 元素
 2 #include <list>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 struct student
 7 {
 8     char* name;        //姓名
 9     int age;        //年龄
10     char* city;        //城市
11     char* tel;        //电话
12 };
13 
14 int main()
15 {
16     student s[]={
17         {"何亮", 18, "北京市", "158 2652 7**4"},
18         {"何小亮", 17, "上海市", "158 2652 7**5"},
19         {"何大亮", 20, "深圳市", "158 2652 7**6"},
20         {"何生亮", 8, "荆州市", "158 2652 7**7"}
21     };
22     // 装入链表数据
23     list<student> lStu;
24     lStu.push_back(s[0]);
25     lStu.push_back(s[1]);
26     lStu.push_back(s[2]);
27     lStu.push_back(s[3]);
28     // 遍历打印链表元素
29     list<student>::iterator i, iend;
30     iend = lStu.end();
31     cout << "姓名    年龄    城市    电话" << endl;
32     cout << "---------------------------" << endl;
33 
34     // 此处,用++i的效率比i++的效率更高。可以参考STL方面的书籍
35     // STL方面的书籍说,后缀++,会产生临时对象,一般不使用;
36     for (i=lStu.begin(); i!=iend; ++i)
37     {
38         cout << (*i).name << "    ";
39         cout << (*i).age << "    ";
40         cout << (*i).city << "    ";
41         cout << (*i).tel << "    ";
42         cout << endl;
43     }
44     cout << "------------------------------------" << endl << endl;
45     
46     return 0;
47 }

 

插入 list 链表元素
 1 /*        解释:
 2     push_back 函数在 list 尾部添加元素;
 3     push_front 函数在 list 链首插入元素;
 4     iterator insert(iterator pos, const T& x) 在任意位置插入元素
 5 */
 6 
 7 -------------------------------------------------------- 插入 list 链表元素
 8 #include <list>
 9 #include <iostream>
10 using namespace std;
11 int main()
12 {
13     list<int> lInt;
14     lInt.push_back(1);
15     lInt.push_back(3);
16     lInt.push_back(4);
17     lInt.push_back(5);
18     // 插入链表元素
19     list<int>::iterator i, iend;
20     i = lInt.begin();
21     ++i;  // 因为是 链表结构,所以,只能通过指针的移位找到要插入的位置
22     lInt.insert(i, 20);  // 在第2个位置,插入元素 20
23     lInt.push_front(0);
24     // 打印链表元素
25     iend = lInt.end();
26     for (i=lInt.begin(); i!=iend; ++i)
27         cout << *i << ' ';
28     cout << endl;
29 
30     return 0;
31 }

 

list 链表元素的删除
 1 /*        解释:
 2     list 同样具有高效的链表元素删除处理,包括删除首元素的 pop_front 函数、删除末尾元素的 pop_back 函数和删除任一【指定迭代器位置】处元素的函数。
 3 1.    void pop_front()    删除 list 的第一个链表元素
 4 2.    void pop_back()     删除 list 的最后一个链表元素
 5 3.    iterator erase(iterator pos)    删除 pos 所指向的链表元素
 6 4.    iterator erase(iterator first, iterator last)    删除迭代器区间 [first, last) 所指向的所有链表元素
 7 5.    void clear()    删除所有 list 链表元素
 8 6.    void remove(const T& value)        删除 list 链表中所有元素值为 value 的元素
 9 */
10 
11 -------------------------------------------------------- list 链表元素的删除
12 #include <list>
13 #include <iostream>
14 using namespace std;
15 int main()
16 {
17     list<int> lInt;
18     lInt.push_back(5);
19     lInt.push_back(6);
20     lInt.push_back(7);
21     lInt.push_back(8);
22     lInt.push_back(9);
23     lInt.push_back(9);
24     lInt.push_back(9);
25     lInt.push_back(10);
26 
27     list<int>::iterator i, iend;
28     i = lInt.begin();
29     ++i;
30     lInt.erase(i);   // 删除 第 2 个元素 6
31     lInt.pop_back();  // 删除末元素 10
32     lInt.pop_front();  // 删除首元素 5
33     lInt.remove(9);  // 删除元素值为 9 的全部元素
34     // 打印    , 剩下 7 和 8
35     iend = lInt.end();
36     for (i=lInt.begin(); i!=iend; ++i)
37         cout << *i << ' ';
38     cout << endl;
39 
40     return 0;
41 }

 

 1 元素的反向遍历:
 2     reverse_iterator  rbegin()
 3     reverse_iterator  rend()
 4     下面代码段,反向遍历 list 链表元素,然后输出
 5 //    list<int>  lInt;
 6     list<int>::reverse_iterator  ri, riend;
 7     riend = lInt.rend();
 8     // 仔细思考
 9     for (ri=lInt.rbegin(); ri!=riend; ++ri)
10         cout << *ri;
11         
12         
13     list 的交换:
14     list容器的 swap 函数,通过简单地交换两个 list 的头指针,来实现 list 元素的交换。交换后的 list 将具有另一个 list 的链表元素。
15     void swap(list&)
16     例如:下面的 list 对象 lIntA 和 lIntB 进行了交换
17     // list<int>  lIntA, lIntB;
18     lIntA.swap(lIntB);
19 
20 
21     补充一个函数 reverse() //反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素

 

 

 

list 链表的归并
 1 /*         解释:
 2     list 的归并
 3     list 链表元素的排序,是将 list 链表分割成若干部分进行子排序,然后通过归并处理,实现 list 的所有元素的排序。为此,list 容器提供了 splice 和 merge 归并函数。
 4 void  splice(iterator position, list& x)        将 x 的链表归并到当前 list 链表的 position 位置之前, list 对象 x 将被清空
 5 void  splice(iterator position, list& x, iterator i)    将一个 list 的迭代器 i 值所指的元素,归并到当前 list 列表中,并将被归并的元素从原链表中删除。
 6 void  merge(list& x)    将 list 对象 x 的链表归并到当前 list 链表中,并清空 x 的链表。从 merge 函数的源码可看出,中有当前 list 链表 和被归并的 x 链表的元素,均预先按照元素值的 "<" 关系排好,merge 函数才具有意义,归并后的链表元素也是按 "<" 关系排序的。
 7 
 8     如下说明 splice 和 merge 函数用法的示例程序,首先依序装入 1~10 的整数到 list 对象 l,然后,调用 list 对象 carry 的 splice 函数获取第 1 个元素,并打印 carry 和 1 的链表元素。创建一个 list 对象 x , 装入排序好的数据,调用 merge 函数将 x 归并到 l , 此时 x 为空,l 变为一个更大的已排好序的 list 对象。
 9 */
10 
11 -------------------------------------------------------- list 链表的归并
12 #include <list>
13 #include <iostream>
14 using namespace std;
15 void print(list<int>& l);
16 int main()
17 {
18     list<int> l;
19     for (int j=1; j<=10; j++)
20     {
21         l.push_back(j);
22     }
23     // splice() 函数
24     list<int> carry;
25     carry.splice(carry.begin(), l, l.begin());
26     // 打印 carry
27     cout << "carry 的链表元素为: ";
28     print(carry);
29     // 打印 l
30     cout << "l 的链表的元素为:";
31     print(l);
32     // merge() 函数用法
33     list<int> x;
34     x.push_back(30);
35     x.push_back(31);
36     x.push_back(32);
37     l.merge(x);
38     // 打印 x
39     cout << "x 的链表元素为空";
40     print(x);
41     // 打印l
42     cout << "l 的链表元素为:";
43     print(l);
44 
45     return 0;
46 }
47 
48 // list 链表打印
49 void print(list<int>& l)
50 {
51     list<int>::iterator i, iend;
52     iend = l.end();
53     for (i=l.begin(); i!=iend; ++i)
54         cout << *i << ' ';
55     cout << endl << endl;
56 }

 

list 链表元素的排序
 1 /*        解释:
 2     list 提供的 void sort 函数,按 "<" 关系进行 list 链表元素排序,较小的元素排在前面。
 3     下面的示例程序将 0~18 的降序排列的整数,依次装入 list 对象 l 的链表中,然后调用 sort 函数,按 0~18 的顺序排序元素。
 4 */
 5 
 6 -------------------------------------------------------- list 链表元素的排序
 7 #include <list>
 8 #include <iostream>
 9 using namespace std;
10 void print(list<int>& l);
11 int main()
12 {
13     list<int> l;
14     for (int j=18; j>=0; j--)
15         l.push_back(j);
16     cout << "排序前:";
17     print(l);
18     // 调用 list<int>::sort() 函数排序
19     l.sort();
20     cout << "排序后";
21     print(l);
22 
23     return 0;
24 }
25 
26 // 打印 list 链表元素
27 void print(list<int>& l)
28 {
29     list<int>::iterator i, iend;
30     iend = l.end();
31     for (i=l.begin(); i!=iend; ++i)
32         cout << *i << ' ';
33     cout << endl;
34 }

 

list 连续重复元素的删除
 1 /*        解释:
 2     利用 list 提供的 void unique 函数,可将连续重复的元素删除。仅保留一个。
 3     例如,下面的示例程序,用 list 对象 l 装入 6 、8 、6 、6 、6 、9 、13 和 6 等整数,然后调用 unique 函数,把中级的 3 个连续元素 “6” 删除,最后打印 “ 6  8  6  9  13  6 ”。
 4 */
 5 
 6 -------------------------------------------------------- list 连续重复元素的删除
 7 #include <list>
 8 #include <iostream>
 9 using namespace std;
10 int main()
11 {
12     list<int> l;
13     l.push_back(6);
14     l.push_back(8);
15     l.push_back(6);
16     l.push_back(6);
17     l.push_back(6);
18     l.push_back(9);
19     l.push_back(13);
20     l.push_back(6);
21 
22     // 去处连续的元素
23     l.unique();
24     list<int>::iterator i, iend;
25     iend = l.end();
26     for (i=l.begin(); i!=iend; ++i)
27         cout << *i << ' ';
28     cout << endl;
29 
30     return 0;
31 }

 

 


-------------------------- list 小结
    list 双向链表容器采用双向链表的数据结构来存储元素数据,可高效查找、插入和删除容器元素。
    list 提供的 splice 和 merge 归并函数,可用于链表的元素排序。sort 函数充分利用 list 的数据结构特点,对元素进行了归并排序。
    
    list 缺点:查找某个元素的时候,经常需要遍历整个链表才能找到。如果,对 查找 的需求很频繁,list 不合适。
    list 优点:元素插入、删除 操作非常频繁的时候,用 list 容器比较合适。

 

 

 

posted @ 2013-04-04 16:25  He_LiangLiang  阅读(1406)  评论(0编辑  收藏  举报