整理了下常用的排序演算法
1、組內有個分享的活動,我整理了常用的排序演算法。講的不太通,備份下,會陸續把程式碼附上。
內部排序:
例子中都是從小到大排序的。
1、 插入排序
1.1、 直接插入排序:將一個記錄插入到一個有序的列表中,得到一個新的,記錄數加一的新的列表。進行關鍵字比較和移動的次數約N^2/4,時間複雜度O(N^2)。
1.2、 折半插入排序:在直接插入排序的基礎上減少比較的次數。其中“查詢”的動作用“折半查詢”來實現。只能減少比較的次數,不能減少移動的次數,時間複雜度O(N^2)。N較大的時候效果明顯。
1.3、 2-路插入排序:在折半插入排序上再改進,減少移動的次數。需要N個輔助空間,如a[N],從小到大排序,將第一個數放在a[0]中,如果比a[0]大,放在後面,如果比a[0]小,放在前面。將陣列a[]看成一個迴圈向量。移動的次數約為
1.4、 希爾排序:主要是通過增量序列中5和3,把整個序列弄的基本有序。以減少排序的比較和移動的次數。【如何取增量序列,和如何計算時間複雜度沒有定論】
2、 快速排序
2.1、 起泡排序:每次比較後,將待排序的數中最大的那個放到最後。比較和移動的次數為N*(N-1)/2。時間複雜度O(N^2)。
2.2、 快速排序:對起泡排序進行改進,每趟排序,將待排記錄中提取一個關鍵字,將其分成兩塊,一塊都比這個關鍵字小,一塊都比這個關鍵字大。遞迴下去,直到結束。時間複雜度O(N*logN)。注意棧的深度。
非遞迴的版本:URL:http://blog.163.com/[email protected]/blog/static/31809050201146113859317/
#include <iostream>
#include <stack>
using namespace std;
template <class T>
int partition(T a[],int low,int high)
{
T v=a[low];
while(low<high)
{
while(low<high && a[high]>=v)
high--;
a[low]=a[high];
while(low<high && a[low]<=v)
low++;
a[high]=a[low];
}
a[low]=v;
return low;
}
template <class T>
void QuickSort(T a[],int p,int q)
{
stack<int> st;
int j;
do{
while(p<q)
{
j=partition(a,p,q);
if( (j-p)<(q-j) )
{
st.push(j+1);
st.push(q);
q=j-1;
}
else
{
st.push(p);
st.push(j-1);
p=j+1;
}
}
if(st.empty())
return;
q=st.top();st.pop();
p=st.top();st.pop();
}while(1);
}
int main()
{
int a[7]={3,5,2,3,1,66,225};
for(int i=0;i<7;i++)
cout<<a[i]<<" ";
cout<<endl;
QuickSort(a,0,6);
for(int i=0;i<7;i++)
cout<<a[i]<<" ";
return 0;
}
3、 選擇排序
3.1、簡單選擇排序:每一趟在N-i+1(I = 1,2….N)中找到最小的作為有序序列的第i個記錄。 關鍵字間比較的次數為N(N-1)/2.時間複雜度為O(N^2)。
3.2、樹形選擇排序:改進的方向是減少比較次數,是因為前一次的比較對後面也是有意 義的。從體育比賽錦標賽中引申而來。時間複雜度為。
3.3、堆形選擇排序:
n個關鍵字序列Kl,K2,…,Kn稱為(Heap),當且僅當該序列滿足如下性質(簡稱 為堆性質):(1)ki<=k(2i)且ki<=k(2i+1)(1≤i≤ n),當然,這是小根堆,大根堆 則換成>=號。//k(i)相當於二叉樹的非葉結點,K(2i)則是左孩子,k(2i+1)是右孩 子完全二叉樹。得到最小的值,然後調整剩下的元素,讓其滿足堆的性質,繼續取出最小值。知道堆中只剩下一個元素為止。適用於較多的數。時間複雜度為:O(N*logN)。
對應的程式碼:
#include <map>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <iostream>
using namespace std;
int NUM = 19;
int a[19] ={0,1,2,3,4,5,6,7,8,0,1,2,3,4,5,6,7,8,0};
//int i代表開始的位置,lenth總的長度
void heapsort(int a[],int i,int lenth)
{
cout<<"i is "<<i<<" lenth is "<<lenth<<" "<<endl;
int tmp = a[i], child = 2*i;
for (; child <= lenth; child *= 2)
{
if ((child + 1 <= lenth ) && (a[child] < a[child+1]))
++child;
if (tmp > a[child])
break;
a[i] = a[child];
i = child;
}
a[i] = tmp;
}
int main()
{
int t,tmp;
int i;
for(i = 0; i < NUM; i++)
cout<<a[i]<<" ";
cout<<endl;
for (t = NUM/2; t > 0; t--)
{
heapsort(a,t,NUM - 1);
for(i = 0; i < NUM; i++)
cout<<a[i]<<" ";
cout<<endl;
}
cout<<"--------------"<<endl;
for (t = NUM - 1; t > 1; t--)
{
tmp = a[1]; a[1]=a[t]; a[t]=tmp;
heapsort(a,1,t-1);
for(i = 0; i < NUM; i++)
cout<<a[i]<<" ";
cout<<endl;
}
}
4、 計數排序: 每次掃描所有的數,將比要排序的數小的數的個數記下來,然後將這個要排序的數放在個數+1的位置。
5、 基數排序:將所有待比較數值(正整數)統一為同樣的數位長度,數位較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後, 數列就變成一個有序序列。基數排序的時間複雜度是O(k·n),其中n是排序元素個數,k是數字位數。
6、 桶排序:假定:輸入是由一個隨機過程產生的[0, 1)區間上均勻分佈的實數。將區間[0, 1)劃分為n個大小相等的子區間(桶),每桶大小1/n:[0, 1/n), [1/n, 2/n), [2/n, 3/n),…,[k/n, (k+1)/n ),…將n個輸入元素分配到這些桶中,對桶中元素進行排序,然後依次連線桶輸入0 ≤A[1..n] <1輔助陣列B[0..n-1]是一指標陣列,指向桶(連結串列)。
7、歸併排序:歸併(Merge)排序法是將兩個(或兩個以上)有序表合併成一個新的有序表。SR[1,2,3,…n],SR中為n個前後相鄰且長度為h的有序序列。時間複雜度為,空間O(n)。其中n是指序列的個數。
外部排序
利用外存對資料檔案進行排序的方法稱為外部排序。
1、 簡單歸併排序。