STL list实现(2)
在之前的一篇文章里,讲述了list的声明和部分函数的实现。(请参考stl list实现一)在这一篇文章里 ,将向大家介绍一些常用函数的实现。
一.
List的删除:list支持删除所有指定的值。 记住,list的remove的参数为VALUE, 不支持参数为iterator.
Erase的参数为迭代器。
为什么remove()和erase()的语义区别这么大呢?我觉得可能与单词的语义有关,remove和erase都是删除。前者偏重于移动,删除。后者偏重于删除,清除。当然,这只是我个人的想法。
template <class T /*, class Alloc*/>
void list<T /*, Alloc*/>::remove(const T& value) {
iterator first = begin(); // 取得头节点
iterator last = end(); // 末尾节点
while (first != last) { // 遍历节点
iterator next = first;
++next;
if (*first == value)
erase(first); // 如果内容匹配,则删除这个节点。
first = next; //
}
}
在这个函数里,临时变量next的作用是保存和恢复first的值。因为再调用erase(first)后,first是会失效的。
二: list的Unique方法
template <class T >
void list<T>::unique()
{
iterator first = begin(); // 取得头节点
iterator last = end(); // 取得end节点
if (first == last) return; //list为空时,返回
iterator next = first; // 临时变量next
while (++next != last) { // 遍历所有节点
if (*first == *next) // 如果相邻两节点相等
erase(next); // 则删除两者中的后者,保留前者
else // 如果不相等,继续
first = next;
next = first; //使next和first保持相等
}
}
由这个实现可以知道,unique只是删除连续相等的元素。所以要使容器的元素不重复,你首先需要调用sort排序。为什么呢? Unique只对已经排好序的容器有效。这一点你必须要注意。用一位哥们的话说,这很干。
带有predicate policy的unique就不再这里说了。道理是一样的。
给个函数的测试用例吧:
#include <iostream>
#include <cmath>
#include <list>
using namespace std;
// 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:
class is_near
{
public:
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 };
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
cout << "mylist contains:";
for (list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it )
cout << " " << *it;
cout << endl;
return 0;
}
三: list的merge
将两个有序的list合并到一起。其中后一个list的元素会被清空。
注意,如果将无序的list合并,请使用slice函数
template <class T >
void list<T>::merge(list<T>& x)
{
iterator first1 = begin(); // 取得第一个list的头
iterator last1 = end(); // 取得第一个list的尾
iterator first2 = x.begin(); //取得第二个list的头
iterator last2 = x.end(); // 取得第二个list的尾
// 该算法思想是:用一个迭代器引用x的元素,另一个迭代器引用和维护另一个list的插入position。如果x的元素比插入位置的元 素小,该元素会被从x中删除并插入到另一个list里。否则 当前插 入点会增加。当任何一个list到达末尾时,以上过程就完成。如果此时x尚未到达末尾,那么则把x剩下的所有元素插入到另一个列表的末尾。
while (first1 != last1 && first2 != last2)
{
if (*first2 < *first1)
{
iterator next = first2;
transfer(first1, first2, ++next);
first2 = next;
} else
++first1;
} // end of while
//如果x还未到达末尾
if (first2 != last2) transfer(last1, first2, last2);
length += x.length;
x.length= 0;
}
List的merge在c语言里也是一个很常见的算法。C++的merge算法和c的merge思想是一致的。
Merge的用法示例:
// list::merge
#include <iostream>
#include <list>
using namespace std;
// this compares equal two doubles if
// their interger equivalents are equal
bool mycomparison (double first, double second)
{ return ( int(first)<int(second) ); }
int main ()
{
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);
second.push_back (2.1);
first.merge(second,mycomparison);
cout << "first contains:";
for (list<double>::iterator it=first.begin(); it!=first.end(); ++it)
cout << " " << *it;
cout << endl;
return 0;
}