C++——std::List

写在前面

这一篇博客系统学习一下C++中List类的相关函数。之所以要学习这个类,是由于LeetCode中做到了Linked List类,虽然在LeetCode中并没有使用到List类的相关函数,而是主要利用链表的数据结构来完成一些内容,或者说,就是从基础的数据结构来实现接下来要学习的一些链表类的函数,比如:插入,删除结点等等。这篇博客的风格内容与之前博客并无两异,所以主要目的还是对List类的主要函数有个印象,在后面做题的时候,万一有遇到类似功能的需求,可以尝试通过函数使用来完成,以便达到简化程序的目的,并且不断强化对于基础类的学习。

list类与头文件包含

列表是序列容器,允许在序列中的任何地方进行恒定的时间插入和擦除操作,并在两个方向上进行迭代。

列表容器被实现为双向链表。双链表可以将它们包含的每个元素存储在不同和不相关的存储位置中。这个顺序是通过关联保存在一个到它之前的元素的链接的每个元素和一个到它之后的元素的链接上。

它们与forward_list非常相似:主要的区别是forward_list对象是单链表,因此它们只能向前迭代,以换取更小更有效的交换。

与其他基本标准序列容器(数组,矢量和双变量)相比,列表通常在已经获得迭代器的容器内的任何位置上插入,提取和移动元素,并且因此在执行密集使用的算法中这些,如排序算法。

列表和forward_lists与这些其他序列容器相比的主要缺点是它们不能直接访问元素的位置;例如,要访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,这需要线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是大型小元素列表的重要因素)。

list类引用:

#include 

list::list

以下代码是list构造的几种方法,代码来自:std::list::list。

// constructing lists
#include 
#include 

int main ()
{
  // constructors used in the same order as described above:
  std::list<int> first;                                // empty list of ints
  std::list<int> second (4,100);                       // four ints with value 100
  std::list<int> third (second.begin(),second.end());  // iterating through second
  std::list<int> fourth (third);                       // a copy of third

  // the iterator constructor can also be used to construct from arrays:
  int myints[] = {16,2,77,29};
  std::list<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );

  std::cout << "The contents of fifth are: ";
  for (std::list<int>::iterator it = fifth.begin(); it != fifth.end(); it++)
    std::cout << *it << ' ';

  std::cout << '\n';

  return 0;
}

list::operator=

将新内容分配给容器,替换其当前内容,并相应地修改其大小。

// assignment operator with lists
#include 
#include 

int main ()
{
  std::list<int> first (3);      // list of 3 zero-initialized ints
  std::list<int> second (5);     // list of 5 zero-initialized ints

  second = first;
  first = std::list<int>();

  std::cout << "Size of first: " << int (first.size()) << '\n';
  std::cout << "Size of second: " << int (second.size()) << '\n';
  return 0;
// Output:
//Size of first: 0
//Size of second: 3
}

int元素的两个列表容器都被初始化为不同大小的序列。 然后,第二个分配给第一个,所以两个现在是相等的,大小为3.然后,首先分配给一个新构建的空容器对象,所以它的大小最终为0。

list-Iterators

list也有迭代器,迭代器(iterator)有时又称游标(cursor)是程序设计的软件设计模式,可在容器(container,例如链表或阵列)上遍访的接口,设计人员无需关心容器的内容。

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。

迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和C/C++“操作array元素”时的指针接口一致。不同之处在于,迭代器是个所谓的复杂的指针,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器型都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义于内部。因此各种迭代器的接口相同,型号却不同。这直接导出了泛型程序设计的概念:所有操作行为都使用相同接口,虽然它们的型别不同。

C++——std::List_第1张图片

利用迭代器也可以实现list的遍历,代码如下:

// list::begin
#include 
#include 

int main ()
{
  int myints[] = {75,23,65,42,13};
  std::list<int> mylist (myints,myints+5);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it != mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: 75 23 65 42 13

list-Capacity:

这里写图片描述

1. list::empty: 判断容器是否为空。该函数无参数,返回值为:如果容器为空,则返回true,如果容器不为空,则返回false。这个函数不会改变容器,如果要清空容器,可以使用函数:list::clear。示例代码通过判断容器不为空,来实现容器的遍历,当然这个方法也可以用于其他容器,比如:vector、set、map等,代码如下:

// list::empty
#include 
#include 

int main ()
{
  std::list<int> mylist;
  int sum (0);

  for (int i=1;i<=10;++i) mylist.push_back(i);

  while (!mylist.empty())
  {
     sum += mylist.front();
     mylist.pop_front();
  }

  std::cout << "total: " << sum << '\n';

  return 0;
}
//Output:
//total: 55

2. list::size: 返回容器所含元素的个数。该函数没有参数传入。示例代码展示了通过list::size()函数来获取容器容量不同的时候容量大小。代码如下:

// list::size
#include 
#include 

int main ()
{
  std::list<int> myints;
  std::cout << "0. size: " << myints.size() << '\n';

  for (int i=0; i<10; i++) myints.push_back(i);
  std::cout << "1. size: " << myints.size() << '\n';

  myints.insert (myints.begin(),10,100);
  std::cout << "2. size: " << myints.size() << '\n';

  myints.pop_back();
  std::cout << "3. size: " << myints.size() << '\n';

  return 0;
}
//Output:
//0. size: 0
//1. size: 10
//2. size: 20
//3. size: 19

3. list::max_size: 返回容器能包含最多的元素数量。由于已知的系统或库实现限制,这是容器可以达到的最大潜在大小,但容器无法保证能够达到该大小:在达到该大小之前的任何时间,仍然无法分配存储。该函数也没有参数传入。示例代码就不展示了,可以参考之前各种容器的同名函数。功能都一样。

list-Element access:

这里写图片描述

1. list::front: 访问第一个元素,返回对列表容器的第一个元素的引用。该函数与list::first不同,后者返回的是一个迭代器,这个迭代器指向同样是第一个元素。而前者返回的是一个元素的引用。需要注意:在空容器上调用此函数会导致未定义的行为。示例代码通过list::front与list::back来获取列表容器一头一尾两个元素,并做运算,说明该函数返回的不是迭代器,是元素的引用。代码如下:

// list::front
#include 
#include 

int main ()
{
  std::list<int> mylist;

  mylist.push_back(77);
  mylist.push_back(22);

  // now front equals 77, and back 22

  mylist.front() -= mylist.back();

  std::cout << "mylist.front() is now " << mylist.front() << '\n';

  return 0;
}
//Output:
//mylist.front() is now 55

2. list::back: 访问列表容器的最后一个元素。并返回该元素的引用。与list::end的区别可以参考list::front与list::begin的区别,在此不赘述。示例代码如上,代码中都有使用list::front与list::back。

list-Modifiers

C++——std::List_第2张图片

1. list::assign: 将新元素内容分配给容器,替换其当前内容,并相应地修改其大小。示例程序通过使用assign函数完成list初始化后的赋值,并通过assign来拷贝一个list创建一个新的list。具体程序如下:

// list::assign
#include 
#include 

int main ()
{
  std::list<int> first;
  std::list<int> second;

  first.assign (7,100);                      // 7 ints with value 100

  second.assign (first.begin(),first.end()); // a copy of first

  int myints[]={1776,7,4};
  first.assign (myints,myints+3);            // assigning from array

  std::cout << "Size of first: " << int (first.size()) << '\n';
  std::cout << "Size of second: " << int (second.size()) << '\n';
  return 0;
}
//Output:
//Size of first: 3
//Size of second: 7

2. list::push_front: 在链表的开头插入元素。就在其当前的第一元素之前。下面示例程序显示了push_front的用法,注意插入元素的位置,插入的元素成为新的第一个元素,原来的第一个元素变为第二个元素。该函数可以说是list特有的,一般容器都是push _ back,所以这个地方可以多注意一点。示例代码如下:

// list::push_front
#include 
#include 

int main ()
{
  std::list<int> mylist (2,100);         // two ints with a value of 100
  mylist.push_front (200);
  mylist.push_front (300);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';
  return 0;
}

//Output:
//300 200 100 100 

3. list::push_back: 在链表的末尾添加一个新的元素。就在当前最后一元素之后。与一般容器的push _back 用法类似。

4. list::pop_front: 删除链表的第一个元素。容器的大小也会相应地减少,此外,被删除的元素会被破坏掉。示例程序使用pop_front一个一个删除链表中所有元素,具体代码如下:

// list::pop_front
#include 
#include 

int main ()
{
  std::list<int> mylist;
  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  std::cout << "Popping out the elements in mylist:";
  while (!mylist.empty())
  {
    std::cout << ' ' << mylist.front();
    mylist.pop_front();
  }

  std::cout << "\nFinal size of mylist is " << mylist.size() << '\n';

  return 0;
}
//Output:
//Popping out the elements in mylist: 100 200 300
//Final size of mylist is 0

5. pop_back: 删除最后一个元素,从list容器中删除最后一个元素,并且相应的将容器的容量减少1.这个函数和其他容器的pop_back函数类似。示例程序通过pop _back函数完成list里所愿元素的删除。具体代码如下:

// list::pop_back
#include 
#include 

int main ()
{
  std::list<int> mylist;
  int sum (0);
  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  while (!mylist.empty())
  {
    sum+=mylist.back();
    mylist.pop_back();
  }

  std::cout << "The elements of mylist summed " << sum << '\n';

  return 0;
}

6. list::emplace: 通过在位置处插入新元素来扩展容器。 这个新元素是用args作为构建的参数来构建的。简单来说,该函数就是通过创建新的元素来在容器中指定位置插入。

// list::emplace
#include 
#include 

int main ()
{
  std::list< std::pair<int,char> > mylist;

  mylist.emplace ( mylist.begin(), 100, 'x' );
  mylist.emplace ( mylist.begin(), 200, 'y' );

  std::cout << "mylist contains:";
  for (auto& x: mylist)
    std::cout << " (" << x.first << "," << x.second << ")";

  std::cout << '\n';
  return 0;
}
//Output:
//mylist contains: (200,y) (100,x)

7. list::emplace_front: 在容器开始处构建并插入元素,在列表的开头插入一个新的元素,就在其当前的第一个元素之前。 这个新元素是用args作为构建的参数来构建的。示例程序实现了只传入元素的参数,并没有考虑元素的数据结构,通过emplace_front函数实现了元素的构造,根据传入的参数。

// list::emplace_front
#include 
#include 

int main ()
{
  std::list< std::pair<int,char> > mylist;

  mylist.emplace_front(10,'a');
  mylist.emplace_front(20,'b');
  mylist.emplace_front(30,'c');

  std::cout << "mylist contains:";
  for (auto& x: mylist)
    std::cout << " (" << x.first << "," << x.second << ")";

  std::cout << std::endl;
  return 0;
}
//Output:
//mylist contains: (30,c) (20,b) (10,a)

8.list::emplace_back: 在容器结尾处构建并插入元素,在列表的最后插入一个新的元素,紧跟在当前的最后一个元素之后。 这个新元素是用args作为构建的参数来构建的。

// list::emplace_back
#include 
#include 

int main ()
{
  std::list< std::pair<int,char> > mylist;

  mylist.emplace_back(10,'a');
  mylist.emplace_back(20,'b');
  mylist.emplace_back(30,'c');

  std::cout << "mylist contains:";
  for (auto& x: mylist)
    std::cout << " (" << x.first << "," << x.second << ")";

  std::cout << std::endl;
  return 0;
}
//Output:
//mylist contains: (10,a) (20,b) (30,c)

9. list::insert: 插入元素,通过在指定位置的元素之前插入新元素来扩展容器。示例程序展现了insert函数的多种用法,具体代码如下:

// inserting into a list
#include 
#include 
#include 

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=5; ++i) mylist.push_back(i); // 1 2 3 4 5

  it = mylist.begin();
  ++it;       // it points now to number 2           ^

  mylist.insert (it,10);                        // 1 10 2 3 4 5

  // "it" still points to number 2                      ^
  mylist.insert (it,2,20);                      // 1 10 20 20 2 3 4 5

  --it;       // it points now to the second 20            ^

  std::vector<int> myvector (2,30);
  mylist.insert (it,myvector.begin(),myvector.end());
                                                // 1 10 20 30 30 20 2 3 4 5
                                                //               ^
  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: 1 10 20 30 30 20 2 3 4 5

10. list::erase: 擦除元素,从列表容器中移除单个元素(位置)或一系列元素([first,last)),调用该函数,容器内元素数量也会相应减少移除元素的数量,移除的元素也会被清理掉。该函数返回一个迭代器指向跟在函数调用擦除的最后一个元素后面的元素。 如果操作删除了序列中的最后一个元素,则返回list.end()。示例程序如下:

// erasing from list
#include 
#include 

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it1,it2;

  // set some values:
  for (int i=1; i<10; ++i) mylist.push_back(i*10);

                              // 10 20 30 40 50 60 70 80 90
  it1 = it2 = mylist.begin(); // ^^
  advance (it2,6);            // ^                 ^
  ++it1;                      //    ^              ^

  it1 = mylist.erase (it1);   // 10 30 40 50 60 70 80 90
                              //    ^           ^

  it2 = mylist.erase (it2);   // 10 30 40 50 60 80 90
                              //    ^           ^

  ++it1;                      //       ^        ^
  --it2;                      //       ^     ^

  mylist.erase (it1,it2);     // 10 30 60 80 90
                              //        ^

  std::cout << "mylist contains:";
  for (it1=mylist.begin(); it1!=mylist.end(); ++it1)
    std::cout << ' ' << *it1;
  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: 10 30 60 80 90

11. list::swap: 交换内容。交换相同类型的列表,虽然列表大小可能不同。在调用这个成员函数之后,这个容器中的元素是那些在调用之前在x中的元素,x的元素就是这个元素中的元素。 所有迭代器,引用和指针对交换对象保持有效。示例程序通过swap函数交换了两个list中的内容。

在已经做过的题目中,可参考:LeetCode-21. Merge Two Sorted Lists。

具体代码如下:

// swap lists
#include 
#include 

int main ()
{
  std::list<int> first (3,100);   // three ints with a value of 100
  std::list<int> second (5,200);  // five ints with a value of 200

  first.swap(second);

  std::cout << "first contains:";
  for (std::list<int>::iterator it=first.begin(); it!=first.end(); it++)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "second contains:";
  for (std::list<int>::iterator it=second.begin(); it!=second.end(); it++)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//first contains: 200 200 200 200 200 
//second contains: 100 100 100 

12. list::resize: 改变容器的大小。调整容器的大小,使其包含n个元素。如果n小于当前的容器大小,内容将被缩小到前n个元素,将其删除(并销毁它们)。如果n大于当前容器大小,则通过在末尾插入尽可能多的元素以达到n的大小来扩展内容。 如果指定了val,则新元素将初始化为val的副本,否则将进行值初始化。示例程序通过resize实现容器大小减小,删除额外元素,或者扩充容器大小,填充默认元素0.具体代码如下:

// resizing list
#include 
#include 

int main ()
{
  std::list<int> mylist;

  // set some initial content:
  for (int i=1; i<10; ++i) mylist.push_back(i);

  mylist.resize(5);
  mylist.resize(8,100);
  mylist.resize(12);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}
//mylist contains: 1 2 3 4 5 100 100 100 0 0 0 0

13. list::clear: 清理一个容器,删除list容器中所有元素。清除完之后容器大小为0。示例程序如下:

// clearing lists
#include 
#include 

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it;

  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  mylist.clear();
  mylist.push_back (1101);
  mylist.push_back (2202);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: 100 200 300
//mylist contains: 1101 2202

list-Operations

C++——std::List_第3张图片

1.list::splice: 将元素从一个list传送到另一个list。这有效地将这些元素插入到容器中,并将它们从x中移除,从而更改了两个容器的大小。 该操作不涉及任何元素的构建或销毁。 无论x是左值还是右值,或者value_type是否支持移动构建,都会被转移。

// splicing lists
#include 
#include 

int main ()
{
  std::list<int> mylist1, mylist2;
  std::list<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=4; ++i)
     mylist1.push_back(i);      // mylist1: 1 2 3 4

  for (int i=1; i<=3; ++i)
     mylist2.push_back(i*10);   // mylist2: 10 20 30

  it = mylist1.begin();
  ++it;                         // points to 2

  mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4
                                // mylist2 (empty)
                                // "it" still points to 2 (the 5th element)

  mylist2.splice (mylist2.begin(),mylist1, it);
                                // mylist1: 1 10 20 30 3 4
                                // mylist2: 2
                                // "it" is now invalid.
  it = mylist1.begin();
  std::advance(it,3);           // "it" points now to 30

  mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end());
                                // mylist1: 30 3 4 1 10 20

  std::cout << "mylist1 contains:";
  for (it=mylist1.begin(); it!=mylist1.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "mylist2 contains:";
  for (it=mylist2.begin(); it!=mylist2.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//mylist1 contains: 30 3 4 1 10 20
//mylist2 contains: 2

2. list::remove: 删除具有特定值的元素,从容器中删除所有比较等于val的元素。 这将调用这些对象的析构函数,并通过删除元素的数量来减小容器大小。与成员函数list :: erase不同(它使用迭代器删除元素的位置),该函数(list :: remove)通过它们的值删除元素。

// remove from list
#include 
#include 

int main ()
{
  int myints[]= {17,89,7,14};
  std::list<int> mylist (myints,myints+4);

  mylist.remove(89);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: 17 7 14

3. list::remove_if: 去除满足条件的元素,从容器中移除Predicate pred返回true的所有元素。 这将调用这些对象的析构函数,并通过删除元素的数量来减小容器大小。该函数调用pred(* i)为每个元素(其中i是该元素的迭代器)。 列表中返回true的任何元素将从容器中移除。示例程序通过实现设定判断真假的函数与结构体类。第一个函数是将数值小于10,返回真值;第二个结构体是创建结构体内函数,函数判断数值是否为偶数,如果是奇数就返回真值。那么remove_if将移除list中使传入参数为真的元素。具体代码如下:

// list::remove_if
#include 
#include 

// a predicate implemented as a function:
bool single_digit (const int& value) { return (value<10); }

// a predicate implemented as a class:
struct is_odd {
  bool operator() (const int& value) { return (value%2)==1; }
};

int main ()
{
  int myints[]= {15,36,7,17,20,39,4,1};
  std::list<int> mylist (myints,myints+8);   // 15 36 7 17 20 39 4 1

  mylist.remove_if (single_digit);           // 15 36 17 20 39

  mylist.remove_if (is_odd());               // 36 20

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

4.list::unique: 删除重复的值.不带参数的版本(1)除去容器中每个连续的相同元素组中的第一个元素。注意,如果一个元素与直接在它之前的元素相等,则它只能从列表容器中移除。 因此,这个函数对排序列表特别有用。

第二个版本(2)以确定元素“唯一性”的特定比较函数作为参数。 实际上,任何行为都可以被实现(而不仅仅是一个等式比较),但是注意函数会调用所有元素对的binary_pred(* i,*(i-1))(其中i是一个元素的迭代器 ,从第二个开始),如果谓词返回true,则从列表中移除i。说白了,带参数的unique是按照(2,1)、(3、2)、(4、3)等顺序检查list中元素的。所以一旦发现有一堆元素满足比较函数要求,那么将首先删除2、3、4,等数对中较大的那一个元素。

示例程序中先用sort函数对list进行排序。然后使用不带参数的unique函数,那么list中的元素前后两两比较,删除重复的元素。然后调用带参数的,也就是比较函数的unique函数。那么将按照比较函数的要求对list中的元素两两做判断,当比较函数返回值为真,则删除。具体代码如下:

// list::unique
#include 
#include 
#include 

// a binary predicate implemented as a function:
bool same_integral_part (double first, double second)
{ return ( int(first)==int(second) ); }

// a binary predicate implemented as a class:
struct is_near {
  bool operator() (double first, double second)
  { return (fabs(first-second)<5.0); }
};

int main ()
{
  double mydoubles[]={ 12.15,  2.72, 73.0,  12.77,  3.14,
                       12.77, 73.35, 72.25, 15.3,  72.25 };
  std::list<double> mylist (mydoubles,mydoubles+10);

  mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,
                             // 15.3,  72.25, 72.25, 73.0,  73.35

  mylist.unique();           //  2.72,  3.14, 12.15, 12.77
                             // 15.3,  72.25, 73.0,  73.35

  mylist.unique (same_integral_part);  //  2.72,  3.14, 12.15
                                       // 15.3,  72.25, 73.0

  mylist.unique (is_near());           //  2.72, 12.15, 72.25

  std::cout << "mylist contains:";
  for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

5. list::merge: 合并排序列表。通过将它们各自的有序位置上的所有元素转移到容器中来将x合并到列表中(这两个容器已经是有序的)。该函数将一个链表中有序的元素与另一个链表中有序的元素进行合并。此时原来的链表已经为空了。而新合并的链表容量也会是原来两个链表容量相加之和。注意,这是merge函数只有一个参数的版本。

如果merge函数有两个参数,那么多出来的一个参数就是一个自定义的比较函数。对于该函数调用之时,需要注意两个链表需要事先已经排好序。如果链表没有排序,那么可以参考函数list::splice()函数。

实例程序使用了上述两种参数传入情况的merge()函数。具体代码如下:

// list::merge
#include 
#include 

// compare only integral part:
bool mycomparison (double first, double second)
{ return ( int(first)<int(second) ); }

int main ()
{
  std::list<double> first, second;

  first.push_back (3.1);
  first.push_back (2.2);
  first.push_back (2.9);

  second.push_back (3.7);
  second.push_back (7.1);
  second.push_back (1.4);

  first.sort();
  second.sort();

  first.merge(second);
  // (first is now :1.4 2.2 2.9 3.1 3.7 7.1)
  // (second is now empty)

  second.push_back (2.1);

  first.merge(second,mycomparison);

  std::cout << "first contains:";
  for (std::list<double>::iterator it=first.begin(); it!=first.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//first contains: 1.4 2.2 2.9 2.1 3.1 3.7 7.1

需要注意的是,比较函数mycomparison只比较两个数的整数部分,所以仔细观察就会发现后插入second的2.1在合并的新的链表中的位置是:2.2 2.9 2.1 3.1,因为,2.1的整数部分为2小于3.1的3,而与2.2、2.9的2相同。

6. list::sort: 将容器内的元素进行排序。对列表中的元素进行排序,改变它们在容器中的位置。通过应用运算符<(一个参数传入)或comp(两个参数传入)中的算法进行排序以比较元素。 这种比较应该产生一个严格的元素弱的顺序(即一致的传递比较,而不考虑其自反性)。等价元素的结果顺序是稳定的,即等价元素保存它们在调用之前的相对顺序。整个操作不涉及任何元素对象的构造,销毁或复制。 元素在容器中移动。

示例程序实现了比较不同的string类型的数据。string的比较规则就是按照string的从前往后的字母的大小比较。如果字母大小完全相同,比如:abc、abcde。那么就按照string长度大小比较。具体代码如下:

// list::sort
#include 
#include 
#include 
#include 

// comparison, not case sensitive.
bool compare_nocase (const std::string& first, const std::string& second)
{
  unsigned int i=0;
  while ( (iif (tolower(first[i])<tolower(second[i])) return true;
    else if (tolower(first[i])>tolower(second[i])) return false;
    ++i;
  }
  return ( first.length() < second.length() );
}

int main ()
{
  std::list<std::string> mylist;
  std::list<std::string>::iterator it;
  mylist.push_back ("one");
  mylist.push_back ("two");
  mylist.push_back ("Three");

  mylist.sort();

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  mylist.sort(compare_nocase);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: Three one two
//mylist contains: one Three two

需要注意:对于默认字符串,比较是一个严格的字符代码比较,其中所有大写字母比较所有小写字母,在第一个排序操作中将所有以大写字母开始的字符串都放在前面。使用函数compare_nocase,比较是不区分大小写的。

7. list::reverse: 颠倒元素的顺序,颠倒列表容器中元素的顺序。示例代码如下:

// reversing list
#include 
#include 

int main ()
{
  std::list<int> mylist;

  for (int i=1; i<10; ++i) mylist.push_back(i);

  mylist.reverse();

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}
//Output:
//mylist contains: 9 8 7 6 5 4 3 2 1

你可能感兴趣的:(C++)