排序演算法總結

2021-07-28 15:38:24 字數 4456 閱讀 6898

知道了很多的排序演算法也許不一定有乙個全域性的把握,為了在應用場景做出更耗的選擇,在此對各種排序演算法做一些總結。

排序分為比較排序和非比較排序,比較排序一般是插入排序,選擇排序,氣泡排序,快速排序,還有反應分而治之的快速排序和歸併排序,比較排序的下界是o(nlog(n))。 而非比較排序時間複雜度可以低至o(n),比如基數排序,計數排序,桶排序,這些排序對資料有特殊的要求。

另一方面我們還要關心排序的穩定性,通常不穩定排序演算法是:

選擇排序o(n^2)

快速排序 o(nlogn)平均時間,o(n^2)是最壞情況

堆排序 o(nlogn)

希爾排序 o(nlogn)

基數排序 o(n-k)

穩定性的排序有

插入排序 o(n^2)

氣泡排序 o(n^2)

歸併排序 o(nlogn)需要o(n)額外儲存空間

計數排序 o(n+k),空間也是o(n+k)

桶排序 o(n) 需要額外o(k)時間

接下來我們介紹這十大排序演算法:

氣泡排序的思路是,每一次從起始位置向右,兩兩比較,如果不符合順序,交換位置,每次冒泡都會在尾部差生乙個當前最大的數,冒泡結束位置一次靠前乙個,以此類推。

這是一種簡單的排序,中間有很多的交換和比較工作。小資料集簡單實用,這個實現是從後往前冒泡的,不過思路沒有差異:

void bublesort(vector

& data)

}

氣泡排序其實可以從兩方面優化

*1 當某一輪兩輛比較中沒有任何元素交換,演算法結束

*2 某一輪中結束位置是j ,該最後一次交換到j之間是有序的,,下一輪結束點可以跳過有序段。

優化**略

這種排序是對氣泡排序的改進,也叫雙向氣泡排序,第一次從左到右冒泡產生右邊最大值,第二次反向產生左邊最小值,若干次來回後元素邊得有序。與氣泡排序相比區別在於,雙向冒泡從高到低從低到高比較,效能要好一些。

**:

void swap(vector

& data, int i, int j)

void whickysort(vector

&data )

i = --end ;

while(i > begin)

begin++;

}}

插入排序思想很重要,首先假定前面一部分已經排好序,當下乙個元素插進來時候作調整,找到合適的位置插入即可,依然有序,這個有序保持到最後就是排序的結果,這種假定可以解決很多的程式設計難題。

void insertsort(vector

& data)

data[j] = val;

}}

選擇排序基本思路是首先找出陣列中最小元素與第乙個元素交換,然後在找出剩下元素最小與第二個元素交換,以此類推。

是一種插入排序的改進,每次新的當前剩餘元素最小元素只需要一次交換即可,而不需要插入排序那樣乙個乙個移動元素騰出地方。

void selectsort(vector

& data)

}

快速排序的思想是分而治之,首先找出乙個基準數,此基準數將陣列一分為三部分,比基準數笑的在左邊,基準數中間,比基準數大的放右邊。再對左右兩邊的部分遞迴呼叫,快速排序是種表現良好的方法,比較常用

void quicksort(vector

&data , int left , int right)

大家都知道topk的問題,蕩資料量很大的時候會得到乙個o(k*logk)*n的解決方案。堆排序的基本思想就是將構建或者調整成堆結構,然後從堆中彈出元素以獲得順序。

首先什麼是堆,一般我們用的是二叉堆,以最小堆為例,它首先是一棵完全二叉樹,任意乙個非葉子節點的左右孩子節點都比它大。空樹也是堆,單獨乙個節點也是堆。我們可以構建乙個堆的類。

給定乙個陣列如何把它調整成乙個堆呢(堆用陣列儲存),首先我們每個葉子節點都是堆,我們只需要調整非葉子節點,按照從右往左,從下層到上層的順序一次往下調整即可。

當插入乙個元素先插入到完全二叉樹最後乙個非葉子節點第乙個空節點,然後向上調整。

當刪除乙個元素時候,取出根節點元素,將最後乙個元素防到根節點,向下調整。

ok,這是heap的類:

struct

heap

void push(int e)

void swap(int i ,int j)

int pop()

int e= data[0];

data[0] = data[data.size()-1];

data.resize(data.size()-1);

//: cout <<"data size = "

}void heapup(int i)

}void heapdown(int i)

}void popprint();

歸併排序也是分而治之的思想,手下將陣列分為左右兩部分分別排序,然後兩部分merge起來。 左右兩部分的排序過程可以遞迴呼叫。

void merge(vector

&data , int left , int mid , int right)

else

} while(i<=mid)tv.push_back(data[i++]);

while(j<=right)tv.push_back(data[j++]);

for(int i = left; i<=right ; i++)data[i]=tv[i-left];

}void mergesort(vector

&data , int left, int right)

這是插入排序的一種改進,針對插入排序數次移動次數較多的問題,希爾排序第一次先從指定步長的子串行作插入排序,依次遞減步長,知道最後一次步長為1的排序時陣列已經基本有序。

void shellsort(vector

& data )

data[k] = val;

}}

如果要排序的數可以作為或者調整後可以作為計數陣列的下標。只是需要很多的額外的空間的限制。

void countsort(vector

&data )

int delt = 0 - minv;

vector

count(maxv - minv +1 , 0);

int k =0;

for(auto i : data)

count[i+delt]++;

for(int i =0 ; i< maxv - minv +1 ; i++)

for(int j = 0 ; j< count[i] ; j++)

data[k++] = i-delt;

}

依次以低位到高位作為key值對陣列進行調整。

int maxdigits(vector

& data)

return count;

}int getbit(int val , int base)

void bsort(vector

& data )

cout

<<"after establish box"

for(auto &i: boxes)

for(auto j : i)

data[k++] = j;

base *= 10;

}}

假設有乙個長度為n的待排自序列k[1…n],首先將這個序列劃分為m個子區間,然後將待排序列的關鍵字k對映到第i個桶,接下來堆

每個桶進行比較排序,然後依次列舉出b[0] b[1] …b[k]元素即是乙個有序的序列。實現中每個桶呼叫了快排序。

void bucketsort(vector

&data, int num)

int delt = 0 - minv ;

int range = maxv - minv +1;

auto bnum = range/num+1;

vector

> buckets(num , vector

());

for(auto i =0 ; i< data.size() ; i++)

buckets[(data[i]+delt)/bnum].push_back(data[i]);

for(auto i =0 ; i< buckets.size() ; i++)

quicksort(buckets[i], 0 , buckets[i].size()-1);

int k =0 ;

for(auto i=0 ; i< buckets.size() ; i++)

for(auto j =0 ; jdata[k++] = buckets[i][j];

}

排序演算法總結

1 直接插入排序 1 穩定性 穩定 2 適用情況 待排記錄規模較小,或者記錄已經基本有序 2 希爾排序 1 穩定性 不穩定 2 特點 希爾排序的執行時間依賴於增量序列,它的效率比直接插入排序有較大的改進。3 氣泡排序 1 穩定性 穩定 2 特點 當待排記錄基本有序是,氣泡排序是不錯的選擇 但由於氣泡...

排序演算法總結

1 選擇排序 選擇排序的思想是依次從待排序數列中選擇最大 小 的 第二大 小 的等等,然後依次重新排列為有序數列。void selectionsort int a,int n if min i 時間複雜度o n 2 2 歸併排序 void merge int a,int left,int mid,i...

排序演算法總結

學習了這麼多的排序演算法,還沒有做個總結,呵呵 氣泡排序 氣泡排序是最慢的排序演算法。在實際運用中它是效率最低的演算法。它通過一趟又一趟地比較陣列中的每乙個元素,使較大的資料下沉,較小的資料上公升。它是 o n 2 的演算法。快速排序 快速排序是乙個就地排序,分而治之,大規模遞迴的演算法。從本質上來...