1. 程式人生 > >常用排序演算法以及時間複雜度

常用排序演算法以及時間複雜度

希爾排序 快速排序 二叉樹排序
氣泡排序 選擇排序 堆排序

#include <iostream.h>

#include <conio.h>

#include <stdlib.h>

#include <time.h>

//折半插入排序

 入口引數:long* Array:指向陣列的指標;long key:關鍵字;long Start:開始索引;long End:結束索引

int HalfSearch(long* Array,long Key,long Start,long End){

long half=(Start+End)/2;    //找折半點

if(Array[half]<=Key && Array[half+1]>Key ) //找到了插入的位置

return half+1;

if(Array[half]>Key) //折半點比關鍵字大,在左邊找

return HalfSearch(Array,Key,Start,half-1);

else

return HalfSearch(Array,Key,half+1,End); //在右邊找

}

void HalfInsSort(long* array/*陣列*/,long leng/*陣列長度*/){

long temp;

long i,j,Pos;

for(i=2;i<=leng;i++){

temp=array[i];//從第二個數開始

j=i-1;//找到前一個數

if((temp<array[j]) && (j>=1)){//如果此處不是TEMP 的正確位置,則折半查詢

Pos=HalfSearch(array,temp,1,j);

while(Pos<=j && Pos!=-1)//移動元素,騰出空間

{array[j+1]=array[j];

j--;}

array[Pos]=temp;//放入適當的位置

}

}

}

//希爾排序,引數解釋同上

void ShellSort(long* array,long leng){

int temp,step;

step=leng/2;//以長度的1/2做為步長,也可以自己設定一個步長序列 

while(step!=0){

for(int i=step+1;i<=leng;i++){//又i來控制迴圈    /*因為從最小步長前面開始排序,前面的

temp=array[i];//從步長數的第二個開始            /*已經有序了,所以象插入排序一樣,只是將後面的

int j=i-step;//找到了前一個的位置    /*小的數插入到前面適當的位置*/

while(temp<array[j] && j>=1){

array[j+step]=array[j];//大的數交換到後面,temp儲存小的數

j=j-step;

}

array[j+step]=temp;//小的數放到適當的位置

}

step=step/2;//再找下一個步長

}

}

//二叉樹排序

//1.陣列表示

/*如果恰好此樹是一個從大到小的序列,則需要的樹空間為2的元素次方個儲存空間*/

/*空間的浪費太大,不划算*/

void BinaryTree(long* btree,/*排序的陣列*/long* array,/*原始陣列*/long leng/*陣列長度*/){

/*建樹的過程就是排序的過程*/

long i;

long parent;

btree[1]=array[1];/*頭接點賦值*/

for(i=2;i<=leng;i++){

parent=1; //確保每次的找插入節點都從ROOT開始

while(btree[parent]!=0){

if(array[i]>btree[parent]) //插入節點大於父節點,則作右孩子

parent=parent*2+1;

else

parent=parent*2; //插入節點小於父節點,則作左孩子

}

btree[parent]=array[i]; //找到正確的位置後插入。返回開始處再找;

}

}

void Inorder(long* btree,/*樹的頭接點*/long pos,/*找到的索引*/long leng/*陣列長*/){ //樹的中序遍歷*/

if(btree[pos]!=0 && pos<=leng){ //由於是陣列表示,所以加上此條件

Inorder(btree,pos*2,leng); //遍歷左孩子

if(btree[pos]!=0)

cout<<btree[pos]<<" "; //列印節點

Inorder(btree,pos*2+1,leng);//遍歷右孩子

}

}

//2.連結串列表示

typedef struct Node{//基本資料結構

Node* left;

long data;

Node* right;

}_Node;

Node* CreateTree(long* array,/*給定的元素*/long leng/*長度*/){

long item;

int leftflag;

Node *root,*parent,*Left=NULL,*Right=NULL;

root=new Node;/*建頭接點*/

root->data=array[1];

root->left=root->right=NULL;

for(item=2;item<=leng;item++){

Node* newnode=new Node; //分配節點

newnode->data=array[item];

newnode->left=newnode->right=NULL;

parent=root;

while(parent!=NULL){

if(newnode->data<parent->data){//如果小於節點的值,到左子樹

if(parent->left==NULL)

Left=parent; //左子樹為空,儲存父節點

parent=parent->left;

leftflag=1;}

else{ if(parent->right==NULL)//右子樹為空,儲存父節點

Right=parent;

parent=parent->right;

leftflag=0;

}

};

if(leftflag==1)//在左子樹

Left->left =newnode;

else//在右子樹

Right->right =newnode;

}

if(root!=NULL)

return root;

else

return NULL;

}

void Inorder(Node* root){//中序遍歷

if(root==NULL)

    return;

Inorder(root->left);

cout<<root->data<<" ";

Inorder(root->right);

}

//交換排序

//1.氣泡排序

void BubbleSort(long* array,long leng){

long i,j;

int finish=0; //是否交換的標誌,如果上一次有交換,此標誌為0,下一次

long temp; //可繼續比較,如果沒有交換,則表示排序完成,不須再比較。這是一個控制排序

//次數的小技巧,可減少排序的時間。

while(!finish){

finish=1; //假定已完成;

for(j=leng;j>=1;j--){//控制次數

for(i=1;i<=j-1;i++){//交換的索引

if(array[i]>array[i+1]){

temp=array[i];

array[i]=array[i+1];

array[i+1]=temp;

finish=0;//有交換,設定標誌位,以便上面的判斷

}

}

}

}

}

//2.快速排序

//基本思想是找一個關鍵字,小於它的放在它的左邊,大於的放在右邊;對兩邊的序列繼續排

void QuickSort(long* array,long low,long high){

long key;

long scanup,scandown;

long temp;

if((high-low)<=0) //設定第一個返回條件

return;

if(high-low==1) //相臨的兩個數要比較是否要交換

if(array[high]>array[low]){//符合條件,交換

temp=array[high];

array[high]=array[low];

array[low]=temp;

return;

}

key=array[low];//一般以最小索引的數做關鍵字

scanup=low;

scandown=high;

do{

while(array[scandown]>=key && scanup<scandown)//向前找到小於關鍵字的數

scandown--;

array[scanup]=array[scandown]; //交換到前面

while(array[scanup]<=key && scanup<scandown)//向後找到大於關鍵字的數

scanup++;

array[scandown]=array[scanup]; //交換到後面

}while(scandown!=scanup); //直到前後的掃描鍵在同一位置為關鍵字的地方

array[scanup]=key;

QuickSort(array,low,scandown-1);//向前快排

QuickSort(array,scanup+1,high);//向後快排

}

/*選擇排序*/

//1.直接選擇排序

void SelectSort(long* array,long leng){

long temp,k;

long i,j;

for(i=1;i<leng;i++){

k=i; //給臨時變數賦值;

for(j=i+1;j<=lung s++)

if(array[k]>=array[j])

k=j; //在此迴圈內找到當前最小值的下標

//只做一次交換;

temp=array[k];

array[k]=array[i];

array[i]=temp;

}

}

//2.堆排序

//基本思想:先由給出的關鍵字來建立一個堆,然後用

void CreateHeap(long* heap,/*陣列表示堆的指標*/long root/*頭接點的序號*/,long leng){//建堆

long child;//孩子接點

long temp;

int finish=0;

child=2*root; //找到子節點

temp=heap[root];

while(child<leng && finish==0){//在子接點的序號小於長度時或不需要交換時退出迴圈

if(child <leng)

if(heap[child]<heap[child+1])

child++; //選出最大的子節點由於交換

if(temp >= heap[child]) //交換完成

finish=1;

else{

heap[child/2]=heap[child]; //交換

child=2*child; //再找下層,直到不滿足迴圈的條件

}

}

heap[child/2]=temp; //節點放入適當的位置

}

void HeapSort(long* heap,long leng){//排序

long i,temp;

for(i=(leng/2);i>=1;i--) //建成大根堆

    CreateHeap(heap,i,leng);

for(i=leng;i>=1;i--){ //排序的方法是:由大根堆的最後一個開始,最後一個是大根堆裡關鍵值最小的一個,它和第一個數交換,將最大的數交換到最後,然後在對剩下的n-1個數進行建堆,重複此過程,使得大的數不斷放到後面,最後使整個序列有序。

temp=heap[i];

heap[i]=heap[1];

heap[1]=temp;

CreateHeap(heap,1,i-1); //對餘下的部分建堆

}

}

                    排序效率比較

排序法

最差時間分析 平均時間複雜度 穩定度 空間複雜度
氣泡排序 O(n2) O(n2) 穩定 O(1)
快速排序 O(n2) O(n*log2n) 不穩定 O(log2n)~O(n)
選擇排序 O(n2) O(n2) 穩定 O(1)
二叉樹排序 O(n2) O(n*log2n) 不一頂 O(n)

插入排序

O(n2) O(n2) 穩定 O(1)
堆排序 O(n*log2n) O(n*log2n) 不穩定 O(1)
希爾排序 O O 不穩定 O(1)