轉載:C++ STL排序演算法
技術標籤:C++
東陽的學習筆記
原文連結:https://www.cnblogs.com/cloudplankroader/p/10434931.html
在介紹排序演算法前,先說明一個可以稱為排序準則的東西,也就是定義strict weak ordering,其意義如下:
1.必須是非對稱的,對operator < 而言,如果x<y是true,則y<x為false。對判斷式op()而言,若op(x,y)為true,則op(x,y)為false。
2.必須是可傳遞的,對operator < 而言,如果x<y是true且y<z為true,則x<z為true。對判斷式op()而言,若op(x,y)為true且op(y,z)為true。
op(x,z)為true。
3.必須是非自反的,對operator < 而言,x<x永遠是false。對判斷式op()而言,op(x,x)永遠為false。
4.必須具有等效傳遞性,大致上來說就是如果ab&&bc,那麼a=c。
STL的排序演算法
stl提供了幾種演算法來對區間內的元素排序,一般分為完全排序(full sorting)和區域性排序(partial sorting)。在可以達到使用目的的情況下,優先使用後者,因為其效能更高。但由於一些關聯式容器(set,map)和無序容器等不提供random-access iterator,所以不適用於這些排序演算法。
但值得注意的是,對全體元素進行一次性排序通常比”始終維護它們保持排序狀態“效率要高,所以具體使用何種容器還要看你所需要的是什麼。
排序演算法標頭檔案
#include<algorithm>
1.完全排序
void
sort(random_access_iterator_beg,random_access_iterator_end)
void
sort(random_access_iterator_beg,random_access_iterator_end,binary_predicate op)
void
stable_sort(random_access_iterator_beg, random_access_iterator_end)
void
stable_sort(random_access_iterator_beg,random_access_iterator_end,binary_predicate op)
- 在這裡有sort()和stable_sort(),它們預設的第一形式都是用operator < 對區間[beg,end)內的所有元素排序。
- sort()和stable_sort()的第二形式使用binary predicate作為排序準則,也就是使用者自己去定義的排序準則。
- 注意,op必須針對元素值定義出strict weak ordering,也就是本文開篇所介紹的內容。
- sort()與stable_sort()的區別在於,後者更加穩定,保證相等的元素的相對次序在排序後不發生改變。
時間複雜度:
sort():平均複雜度nlogn,最壞n^2。
stable_sort():若記憶體足夠,則就是nlogn,不會變化。若沒有足夠記憶體,則複雜度是2nlogn。
比較常用的sort結構體排序
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int num1,num2;
}arr[10000];
bool cmp(node a,node b)//自定義比較準則
{
return a.num1<b.num1;//以num1較小者優先排列
}
int main()
{
arr[0]={1,2};
arr[1]={2,1};
arr[2]={3,4};
arr[3]={4,3};
sort(arr,arr+4,cmp);//嚴格按照要求傳入引數
for(int i=0;i<4;++i)
{
cout<<arr[i].num1<<" ";
}
cout<<endl;
for(int i=0;i<4;++i)
{
cout<<arr[i].num2<<" ";
} return 0;
}
2.區域性排序
void
partial_sort(random_access_iterator_beg,random_access_iterator_sortend,random_access_iterator_end)
void
partial_sort(random_access_iterator_beg,random_access_iterator_sortend,random_access_iterator_end,binary_predicate op)
- 第一形式以operator < 對[beg,end)區間內元素進行排序,使[beg,sortend)區間內元素處於有序狀態。
- 第二形式使用binary predicate作為排序準則,也就是使用者自己去定義的排序準則。
- 除了與sort所需要注意的相同外,partial_sort()並不對全部元素排序,你傳入的引數分別是排序首部,排序尾部,整體區間尾部。它會按照你所指示的區間進行排序,不用進行多餘的操作。
- 如果sortend等於end的話,那麼partial_sort()會對整個序列排序,平均而言其效能不及sort(),但最差情況則優於sort()。
時間複雜度:線上性與nlogn之間。
3.根據第n個元素排序
快速排序的一次patation操作
void
nth_element(random_access_iterator_beg,random_access_iterator_nth,random_access_iterator_end)
void
nth_element(random_access_iterator_beg,random_access_iterator_nth,random_access_iterator_end,binary_predicate op)
兩種形式都對[beg,end)區間內的元素排序,使第n個位置上的元素就位,也就是說,在位置n之前的元素都小於等於它,所有之後的元素都大於等於它。這樣,你就得到了”根據n位置上的元素“分割開來的兩個子序列,第一子序列的元素統統小於第二子序列的元素,但是處於無序狀態。同樣的,該演算法也提供自定義排序準則。
時間複雜度:平均為線性。
nth_element操作舉例
#include<iostream>
#include<algorithm>
bool cmp(int a,int b)
{
return a>b;
}
using namespace std;
int main()
{
int a[]={1,5,6,2,9,7,3,4,10,8};
int elem=a[2];
nth_element(a, a+3, a+10);//第一種形式,預設為<
int i=0;
while(a[i]<elem)
{
cout<<a[i]<<" ";
i++;
}
cout<<endl;
int b[]={1,5,6,2,9,7,3,4,10,8};
nth_element(b,b+3,b+10,cmp);//傳入過載函式
int j=0;
while(b[j]>elem)
{
cout<<b[j]<<" ";
j++;
}
}
執行結果
由此可見雖然分割出了序列,但順序是打亂的。
Heap 演算法
即堆排序演算法。heap 可被視為一個以序列式群集實作而成的二叉樹
,具有兩大性質。
- 第一個元素總是最大
- 總是能在
對數時間
內增加或移除一個元素
heap是實作 priority queue(其內元素會自動排序)的一個理想結構。因此,heap演算法在 priority_queue 容器中有所應用。為了處理 heap, STL提供以下四種演算法:
- make_heap() 將某區間內的元素按照某種準則轉化為 heap
- push_heap() 對heap增加一個元素
- pop_heap() 對著heap取出下一個元素
- sort_heap() 將heap轉化為一個已序群集(此後他便不再是heap了)