STL sort()函数

C++之因此获得这么多人的喜欢,是由于它既具备面向对象的概念,又保持了C语言高效的特色。STL 排序算法一样须要保持高效。所以,对于不一样的需求,STL提供的不一样的函数,不一样的函数,实现的算法又不尽相同。php

1.1 全部sort算法介绍

全部的sort算法的参数都须要输入一个范围,[begin, end)。这里使用的迭代器(iterator)都需是随机迭代器(RadomAccessIterator), 也就是说能够随机访问的迭代器,如:it+n什么的。(partition 和stable_partition 除外)html

若是你须要本身定义比较函数,你能够把你定义好的仿函数(functor)做为参数传入。每种算法都支持传入比较函数。如下是全部STL sort算法函数的名字列表:ios

函数名 功能描述
sort 对给定区间全部元素进行排序
stable_sort 对给定区间全部元素进行稳定排序
partial_sort 对给定区间全部元素部分排序
partial_sort_copy 对给定区间复制并排序
nth_element 找出给定区间的某个位置对应的元素
is_sorted 判断一个区间是否已经排好序
partition 使得符合某个条件的元素放在前面
stable_partition 相对稳定的使得符合某个条件的元素放在前面

其中nth_element 是最不易理解的,实际上,这个函数是用来找出第几个。例如:找出包含7个元素的数组中排在中间那个数的值,此时,我可能不关心前面,也不关心后面,我只关心排在第四位的元素值是多少。web

1.2 sort 中的比较函数

当你须要按照某种特定方式进行排序时,你须要给sort指定比较函数,不然程序会自动提供给你一个比较函数。面试

vector < int > vect;
//...
sort(vect.begin(), vect.end());
//此时至关于调用
sort(vect.begin(), vect.end(), less<int>() );

上述例子中系统本身为sort提供了less仿函数。在STL中还提供了其余仿函数,如下是仿函数列表:算法

名称 功能描述
equal_to 相等
not_equal_to 不相等
less 小于
greater 大于
less_equal 小于等于
greater_equal 大于等于

须要注意的是,这些函数不是都能适用于你的sort算法,如何选择,决定于你的应用。另外,不能直接写入仿函数的名字,而是要写其重载的()函数:数组

less<int>()
greater<int>()

当你的容器中元素时一些标准类型(int float char)或者string时,你能够直接使用这些函数模板。但若是你时本身定义的类型或者你须要按照其余方式排序,你能够有两种方法来达到效果:一种是本身写比较函数。另外一种是重载类型的'<'操做赋。数据结构

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;

class myclass {
        public:
        myclass(int a, int b):first(a), second(b){}
        int first;
        int second;
        bool operator < (const myclass &m)const {
                return first < m.first;
        }
};

bool less_second(const myclass & m1, const myclass & m2) {
        return m1.second < m2.second;
}

int main() {
        
        vector< myclass > vect;
        for(int i = 0 ; i < 10 ; i ++){
                myclass my(10-i, i*3);
                vect.push_back(my);
        }
        for(int i = 0 ; i < vect.size(); i ++) 
        cout<<"("<<vect[i].first<<","<<vect[i].second<<")\n";
        sort(vect.begin(), vect.end());
        cout<<"after sorted by first:"<<endl;
        for(int i = 0 ; i < vect.size(); i ++) 
        cout<<"("<<vect[i].first<<","<<vect[i].second<<")\n";
        cout<<"after sorted by second:"<<endl;
        sort(vect.begin(), vect.end(), less_second);
        for(int i = 0 ; i < vect.size(); i ++) 
        cout<<"("<<vect[i].first<<","<<vect[i].second<<")\n";
        
        return 0 ;
}

知道其输出结果是什么了吧:app

(10,0)
(9,3)
(8,6)
(7,9)
(6,12)
(5,15)
(4,18)
(3,21)
(2,24)
(1,27)
after sorted by first:
(1,27)
(2,24)
(3,21)
(4,18)
(5,15)
(6,12)
(7,9)
(8,6)
(9,3)
(10,0)
after sorted by second:
(10,0)
(9,3)
(8,6)
(7,9)
(6,12)
(5,15)
(4,18)
(3,21)
(2,24)
(1,27)

1.3 sort 的稳定性

你发现有sort和stable_sort,还有 partition 和stable_partition, 感到奇怪吧。其中的区别是,带有stable的函数可保证相等元素的本来相对次序在排序后保持不变。或许你会问,既然相等,你还管他相对位置呢,也分不清楚谁是谁了?这里须要弄清楚一个问题,这里的相等,是指你提供的函数表示两个元素相等,并不必定是一摸同样的元素。less

例如,若是你写一个比较函数:

bool less_len(const string &str1, const string &str2)
{
        return str1.length() < str2.length();
}

此时,"apple" 和 "winter" 就是相等的,若是在"apple" 出如今"winter"前面,用带stable的函数排序后,他们的次序必定不变,若是你使用的是不带"stable"的函数排序,那么排序完后,"Winter"有可能在"apple"的前面。

 

1.4 全排序

全排序即把所给定范围全部的元素按照大小关系顺序排列。用于全排序的函数有

 

template <class RandomAccessIterator>
void sort(RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class StrictWeakOrdering>
void sort(RandomAccessIterator first, RandomAccessIterator last,
StrictWeakOrdering comp);

template <class RandomAccessIterator>
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class StrictWeakOrdering>
void stable_sort(RandomAccessIterator first, RandomAccessIterator last, 
StrictWeakOrdering comp);

在第1,3种形式中,sort 和 stable_sort都没有指定比较函数,系统会默认使用operator< 对区间[first,last)内的全部元素进行排序, 所以,若是你使用的类型义军已经重载了operator<函数,那么你能够省心了。第2, 4种形式,你能够随意指定比较函数,应用更为灵活一些。来看看实际应用:

班上有10个学生,我想知道他们的成绩排名。

#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <string>
using namespace std;

class student{
        public:
        student(const string &a, int b):name(a), score(b){}
        string name;
        int score;
        bool operator < (const student &m)const {
                return score< m.score;
        }
};

int main() {
        vector< student> vect;
        student st1("Tom", 74);
        vect.push_back(st1);
        st1.name="Jimy";
        st1.score=56;
        vect.push_back(st1);
        st1.name="Mary";
        st1.score=92;
        vect.push_back(st1);
        st1.name="Jessy";
        st1.score=85;
        vect.push_back(st1);
        st1.name="Jone";
        st1.score=56;
        vect.push_back(st1);
        st1.name="Bush";
        st1.score=52;
        vect.push_back(st1);
        st1.name="Winter";
        st1.score=77;
        vect.push_back(st1);
        st1.name="Andyer";
        st1.score=63;
        vect.push_back(st1);
        st1.name="Lily";
        st1.score=76;
        vect.push_back(st1);
        st1.name="Maryia";
        st1.score=89;
        vect.push_back(st1);
        cout<<"------before sort..."<<endl;
        for(int i = 0 ; i < vect.size(); i ++) cout<<vect[i].name<<":\t"<<vect[i].score<<endl;
        stable_sort(vect.begin(), vect.end(),less<student>());
        cout <<"-----after sort ...."<<endl;
        for(int i = 0 ; i < vect.size(); i ++) cout<<vect[i].name<<":\t"<<vect[i].score<<endl;
        return 0 ;
}

其输出是:

------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Bush:   52
Jimy:   56
Jone:   56
Andyer: 63
Tom:    74
Lily:   76
Winter: 77
Jessy:  85
Maryia: 89
Mary:   92

sort采用的是成熟的"快速排序算法"(目前大部分STL版本已经不是采用简单的快速排序,而是结合内插排序算法)。注1,能够保证很好的平均性能、复杂度为n*log(n),因为单纯的快速排序在理论上有最差的状况,性能很低,其算法复杂度为n*n,但目前大部分的STL版本都已经在这方面作了优化,所以你能够放心使用。stable_sort采用的是"归并排序",分派足够内存是,其算法复杂度为n*log(n), 不然其复杂度为n*log(n)*log(n),其优势是会保持相等元素之间的相对位置在排序先后保持一致。

1.5 局部排序

局部排序实际上是为了减小没必要要的操做而提供的排序方式。其函数原型为:

template <class RandomAccessIterator>
void partial_sort(RandomAccessIterator first, 
RandomAccessIterator middle,
RandomAccessIterator last);

template <class RandomAccessIterator, class StrictWeakOrdering>
void partial_sort(RandomAccessIterator first,
RandomAccessIterator middle,
RandomAccessIterator last, 
StrictWeakOrdering comp);

template <class InputIterator, class RandomAccessIterator>
RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last,
RandomAccessIterator result_first,
RandomAccessIterator result_last);

template <class InputIterator, class RandomAccessIterator, 
class StrictWeakOrdering>
RandomAccessIterator partial_sort_copy(InputIterator first, InputIterator last,
RandomAccessIterator result_first,
RandomAccessIterator result_last, Compare comp);

理解了sort 和stable_sort后,再来理解partial_sort 就比较容易了。先看看其用途: 班上有10个学生,我想知道分数最低的5名是哪些人。若是没有partial_sort,你就须要用sort把全部人排好序,而后再取前5个。如今你只须要对分数最低5名排序,把上面的程序作以下修改:

stable_sort(vect.begin(), vect.end(),less<student>());
替换为:
partial_sort(vect.begin(), vect.begin()+5, vect.end(),less<student>());

输出结果为:

------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Bush:   52
Jimy:   56
Jone:   56
Andyer: 63
Tom:    74
Mary:   92
Jessy:  85
Winter: 77
Lily:   76
Maryia: 89

这样的好处知道了吗?当数据量小的时候可能看不出优点,若是是100万学生,我想找分数最少的5我的......

partial_sort采用的堆排序(heapsort),它在任何状况下的复杂度都是n*log(n). 若是你但愿用partial_sort来实现全排序,你只要让middle=last就能够了。

partial_sort_copy实际上是copy和partial_sort的组合。被排序(被复制)的数量是[first, last)和[result_first, result_last)中区间较小的那个。若是[result_first, result_last)区间大于[first, last)区间,那么partial_sort至关于copy和sort的组合。

1.6 nth_element 指定元素排序

nth_element一个容易看懂但解释比较麻烦的排序。用例子说会更方便:
班上有10个学生,我想知道分数排在倒数第4名的学生。
若是要知足上述需求,能够用sort排好序,而后取第4位(由于是由小到大排), 更聪明的朋友会用partial_sort, 只排前4位,而后获得第4位。其实这是你仍是浪费,由于前两位你根本没有必要排序,此时,你就须要nth_element:

template <class RandomAccessIterator>
void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
RandomAccessIterator last);

template <class RandomAccessIterator, class StrictWeakOrdering>
void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
RandomAccessIterator last, StrictWeakOrdering comp);

对于上述实例需求,你只须要按下面要求修改1.4中的程序:

stable_sort(vect.begin(), vect.end(),less<student>());
替换为:
nth_element(vect.begin(), vect.begin()+3, vect.end(),less<student>());

运行结果为:

------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Jone:   56
Bush:   52
Jimy:   56
Andyer: 63
Jessy:  85
Mary:   92
Winter: 77
Tom:    74
Lily:   76
Maryia: 89

第四个是谁?Andyer,这个倒霉的家伙。为何是begin()+3而不是+4? 我开始写这篇文章的时候也没有在乎,后来在ilovevc 的提醒下,发现了这个问题。begin()是第一个,begin()+1是第二个,... begin()+3固然就是第四个了。

1.7 partition 和stable_partition

好像这两个函数并非用来排序的,'分类'算法,会更加贴切一些。partition就是把一个区间中的元素按照某个条件分红两类。其函数原型为:

template <class ForwardIterator, class Predicate>
ForwardIterator partition(ForwardIterator first,
ForwardIterator last, Predicate pred)
template <class ForwardIterator, class Predicate>
ForwardIterator stable_partition(ForwardIterator first, ForwardIterator last, 
Predicate pred);

看看应用吧:班上10个学生,计算全部没有及格(低于60分)的学生。你只须要按照下面格式替换1.4中的程序:

stable_sort(vect.begin(), vect.end(),less<student>());
替换为:
student exam("pass", 60);
stable_partition(vect.begin(), vect.end(), bind2nd(less<student>(), exam));

其输出结果为:

------before sort...
Tom:    74
Jimy:   56
Mary:   92
Jessy:  85
Jone:   56
Bush:   52
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89
-----after sort ....
Jimy:   56
Jone:   56
Bush:   52
Tom:    74
Mary:   92
Jessy:  85
Winter: 77
Andyer: 63
Lily:   76
Maryia: 89

看见了吗,Jimy,Jone, Bush(难怪说美国总统比较笨 smile )都没有及格。并且使用的是stable_partition, 元素之间的相对次序是没有变.

2 Sort 和容器


STL中标准容器主要vector, list, deque, string, set, multiset, map, multimay, 其中set, multiset, map, multimap都是以树结构的方式存储其元素详细内容请参看:学习STL map, STL set之数据结构基础. 所以在这些容器中,元素一直是有序的。

这些容器的迭代器类型并非随机型迭代器,所以,上述的那些排序函数,对于这些容器是不可用的。上述sort函数对于下列容器是可用的:

  • vector
  • string
  • deque

若是你本身定义的容器也支持随机型迭代器,那么使用排序算法是没有任何问题的。

对于list容器,list自带一个sort成员函数list::sort(). 它和算法函数中的sort差很少,可是list::sort是基于指针的方式排序,也就是说,全部的数据移动和比较都是此用指针的方式实现,所以排序后的迭代器一直保持有效(vector中sort后的迭代器会失效).

 

3 选择合适的排序函数


为何要选择合适的排序函数?可能你并不关心效率(这里的效率指的是程序运行时间), 或者说你的数据量很小, 所以你以为随便用哪一个函数都可有可无。

其实否则,即便你不关心效率,若是你选择合适的排序函数,你会让你的代码更容易让人明白,你会让你的代码更有扩充性,逐渐养成一个良好的习惯,很重要吧 smile 。

若是你之前有用过C语言中的qsort, 想知道qsort和他们的比较,那我告诉你,qsort和sort是同样的,由于他们采用的都是快速排序。从效率上看,如下几种sort算法的是一个排序,效率由高到低(耗时由小变大):

  1. partion
  2. stable_partition
  3. nth_element
  4. partial_sort
  5. sort
  6. stable_sort

记得,之前翻译过Effective STL的文章,其中对如何选择排序函数总结的很好:

  • 若需对vector, string, deque, 或 array容器进行全排序,你可选择sort或stable_sort;
  • 若只需对vector, string, deque, 或 array容器中取得top n的元素,部分排序partial_sort是首选.
  • 若对于vector, string, deque, 或array容器,你须要找到第n个位置的元素或者你须要获得top n且不关系top n中的内部顺序,nth_element是最理想的;
  • 若你须要从标准序列容器或者array中把知足某个条件或者不知足某个条件的元素分开,你最好使用partition或stable_partition;
  • 若使用的list容器,你能够直接使用partition和stable_partition算法,你可使用list::sort代替sort和stable_sort排序。若你须要获得partial_sort或nth_element的排序效果,你必须间接使用。正如上面介绍的有几种方式能够选择。

总之记住一句话: 若是你想节约时间,不要走弯路, 也不要走多余的路!

4 小结


讨论技术就像个无底洞,常常容易由一点能够引伸另外无数个技术点。所以须要从全局的角度来观察问题,就像观察STL中的sort算法同样。其实在STL还有make_heap, sort_heap等排序算法。本文章没有提到。本文以实例的方式,解释了STL中排序算法的特性,并总结了在实际状况下应如何选择合适的算法。


队列中取最大值操做

假设有这样一个拥有3个操做的队列:

    1.EnQueue(v):将v加入队列
    2.DeQueue:使队列中的队首元素删除并返回元素
    3.MaxElement:返回队列中的最大元素
请设计一种数据结构和算法,让MaxElement操做的时间复杂度尽量低
 
研究这个问题以前,先研究两个子问题:
    一、设计一个包含min操做的栈
    二、用栈实现队列
 
1、设计一个包含min操做的栈
    考虑给栈增长一个成员变量MinValue,有元素入栈的时候,将入栈元素与MinValue相比,若是小于MinValue,用入栈元素的值,更新MinValue,可是效率低的地方在于,若是出栈元素等于MinValue,则须要从新查找整个栈,找出MinValue。
    解决这个问题的方法是采用一个辅助栈,将一个元素入栈的时候,在辅助栈中相同的位置记录它入栈以前栈中最小元素的位置。出栈的时候,若出栈元素等于MinValue,则查找这个辅助栈对应项的元素,直接按位置取出最小值。
如图:
    

队列中取最大值操做


最左边的数字表明元素在栈中的位置。当3入栈时,它就是最小元素,所以在辅助栈中与它位置相同的地方,保存它以前的最大位置(-1或0皆可),4入栈的时候,考虑到3和help[0]相等,所以4对应的辅助栈元素是0,2入栈时,考虑到4大于stack[help[1]],所以2对应的辅助栈元素仍然是0,1入栈时,因为2比stack[help[2]]小,所以1对应的辅助栈元素是2的位置,即2.依次类推。

源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
template < typename  T>  class  MinStack {
private :
     T *stack;
     T *min;
     size_t  top;
     T MinValue;
     size_t  MaxElement;
public :
     MinStack();
     ~MinStack();
     void  push(T t);
     void  pop();
     T GetTop();
     T GetMin();
};
template < typename  T> MinStack<T>::MinStack()
{
     MaxElement = 20;
     stack =  new  T[MaxElement];
     min =  new  T[MaxElement];
     top = -1;
}
  
template < typename  T> MinStack<T>::~MinStack()
{
     delete [] stack;
     delete [] min;
}
  
template < typename  T>  void  MinStack<T>::push(T t)
{
     if (top == MaxElement)
     {
         cout<< "It's full" ;
         return ;
     }
     if (top == -1)
     {
         stack[++top] = t;
         min[top] = 0;
         MinValue = t;
     }
     else
     {
         stack[++top] = t;
         min[top] = stack[top-1]>stack[min[top-1]]?min[top-1]:top-1;
         MinValue = t>stack[min[top]]?stack[min[top]]:t;
     }
}
  
template < typename  T>  void  MinStack<T>::pop()
{
     if (top==-1)
     {
         cout<< "It's empty" ;
         return ;
     }
     if (top == 0)
     {
         --top;
     }
     else
     {
         --top;
         MinValue = stack[min[top+1]];
     }
}
  
template < typename  T> T MinStack<T>::GetTop()
{
     if (top==-1)
     {
         cout<< "It's empty stack" ;
         exit (0);
     }
     return  stack[top];
}
  
template < typename  T> T MinStack<T>::GetMin()
{
     if (top==-1)
     {
         cout<< "It's empty stack" ;
         exit (0);
     }
     return  MinValue;
}
2、用两个栈实现队列
这个问题的关键是,设置一个栈用来入队,另外一个栈用来出队。一开始出栈队为空,当有出队动做的时候,就将入队栈所有出栈,进栈到出队栈,这样顺序就正好反过来了,下一次出队就直接从出队栈取元素,入队则继续入入队栈。总结一下就是:
    入队一直是在入队栈入栈。
    出队的时候,若是出队栈为空,就把入队栈所有出栈入栈到出队栈,再取栈顶元素,移动栈顶指针,若是出队栈不空,直接取元素,移指针。
源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
template < typename  T>  class  Stack
{
public :
     T *s;
     size_t  top;
     size_t  Max;
     Stack();
     ~Stack();
     void  push(T t);
     void  pop();
     T GetTop();
};
  
template < typename  T>  class  Queue
{
private :
     Stack<T> En;
     Stack<T> De;
public :   
     void  EnQueue(T t);
     T DeQueue();
};
template < typename  T> Stack<T>::Stack()
{
     Max = 20;
     s =  new  T[Max];
     top = -1;
}
  
template < typename  T> Stack<T>::~Stack()
{
     delete [] s;
}
  
template < typename  T>  void  Stack<T>::push(T t)
{
     if (top==Max)
     {
         cout<< "It's full stack" ;
         return ;
     }
     s[++top] = t;
}
  
template < typename  T>  void  Stack<T>::pop()
{
     if (top == -1)
     {
         cout<< "It's empty stack" ;
         return ;
     }
     --top;
}
  
template < typename  T> T Stack<T>::GetTop()
{
     return  s[top];
}
  
template < typename  T>  void  Queue<T>::EnQueue(T t)
{
     En.push(t);
}
  
template < typename  T> T Queue<T>::DeQueue()
{
     if (De.top==-1)
     {
         while (En.top+1>0)
         {
             De.push(En.GetTop());
             En.pop();
         }
     }
     if (De.top==-1)
     {
         cout<< "It's empty queue" ;
     }
     T temp = De.GetTop();
     De.pop();
     return  temp;
}
解决了这两个子问题以后,队列中取最大值操做便迎刃而解。
修改Queue的定义,用MinStack代替Stack,并加入一个MinValue()函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
template < typename  T>  class  Queue
{
private :
     MinStack<T> En;
     MinStack<T> De;
public :
     void  EnQueue(T t);
     T DeQueue();
     T MinValue();
};
  
template < typename  T> T Queue<T>::MinValue()
{
     if (De.top==-1&&En.top==-1)
     {
         cout<< "It's a empty queue" ;
         exit (0);
     }
     else  if (De.top == -1)
     {
         return  En.MinValue;
     }
     else  if (En.top == -1)
     {
         return  De.MinValue;
     }
     else
     {
         return  En.MinValue<De.MinValue?En.MinValue:De.MinValue;
     }
}
若是不用模板,直接用int或者float,则能够将MinStack中的MinValue值初始化为INT_MAX,而且若是队空就将MinValue置为INT_MIN,这样能够省略En空,De不空或者En不空De空的讨论。
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//问题:设计一个队列可以在O(1)时间内取得队列的最大值
 
#include <stdio.h>
#include <queue>
#include <stack>
 
//O(1)的速度取出栈中的最大值
template < typename  T>
class  MaxStack
{
public :
     //入栈
     void  Push( const  T& value)
     {
         data_.push(value);
         if  (max_element_.empty())
         {
             max_element_.push(value);
         }
         else  if  (value >= max_element_.top())
         {
             max_element_.push(value);
         }
     }
     //返回栈顶元素
     T Top()
     {
         return  data_.top();
     }
     //出栈
     void  Pop()
     {
         if  (data_.top() == max_element_.top())
         {
             max_element_.pop();
         }
         data_.pop();   
      }
     //判断是否为空
      bool  Empty()
      {
          return  data_.empty();
      }
      //取出最大值
      T Max()
      {
          if  (!max_element_.empty())
          {
              return  max_element_.top();
          }
      }
private :
     std::stack<T> data_;
     std::stack<T> max_element_;
};
 
//O(1)的速度取出队列中的最大值
template < typename  T>
class  MaxQueue
{
public :
     
     //入队操做!!!!
     void  Push( const  T& value)
     {
         push_stack_.Push(value);
     }
 
     //取队首元素
     T Front()
     {
         if  (pop_stack_.empty())
         {
             while  (!push_stack_.Empty())
             {
                 pop_stack_.Push(push_stack_.Top());
                 push_stack_.Pop();
             }
         }
         return  pop_stack_.Top();
     }
 
     //出队操做!!!!
     void  Pop()
     {
         if  (pop_stack_.Empty())
         {
             while  (!push_stack_.Empty())
             {
                 pop_stack_.Push(push_stack_.Top());
                 push_stack_.Pop();
             }
         }
         pop_stack_.Pop();
     }
 
     //判空操做!!!!!
     bool  IsEmpty()
     {
         return  push_stack_.Empty() && pop_stack_.Empty();
     }
 
     //取出最大值
     T Max()
     {
         if  (!push_stack_.Empty() && !pop_stack_.Empty())
         {
             return  push_stack_.Max() > pop_stack_.Max() ? push_stack_.Max() : pop_stack_.Max();
         }
         else  if  (push_stack_.Empty() && !pop_stack_.Empty())
         {
             return  pop_stack_.Max();
         }
         else  if  (!push_stack_.Empty() && pop_stack_.Empty())
         {
             return  push_stack_.Max();
         }
         else   
         {
               throw  RUNTIME_ERROR;
         }
     }
private :
     MaxStack<T> push_stack_;
     MaxStack<T> pop_stack_;
};
//测试用例
int  main( int  argc,  char ** argv)
{
     MaxQueue< int > max_queue;
     max_queue.Push(1);
     max_queue.Push(2);
     max_queue.Push(6);
     max_queue.Push(4);
     max_queue.Push(5);
     max_queue.Push(2);
     printf ( "max %d\n" , max_queue.Max());
     max_queue.Pop();
     printf ( "max %d\n" , max_queue.Max());
     max_queue.Pop();
     printf ( "max %d\n" , max_queue.Max());
     max_queue.Pop();
     printf ( "max %d\n" , max_queue.Max());
     max_queue.Pop();
     printf ( "max %d\n" , max_queue.Max());
     max_queue.Pop();
     printf ( "max %d\n" , max_queue.Max());
}

  

posted @  2015-05-12 12:13  Vae永Silence 阅读( 1) 评论( 0编辑  收藏
相关文章
相关标签/搜索