排序法
最差時間分析
平均時間複雜度
穩定度
空間複雜度
氣泡排序
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)
希爾排序
oo (n的1.2次冪)
不穩定
o(1)
歸併排序
o(nlogn)
o(n*log2n)
穩定 o(n)
基數排序
o(d(n+rd))
o (d(n+rd))
穩定 o(rd)
注:選擇排序:在找那個最小的元素時,如果是從前向後找,那麼就是不穩定的;如果是從後往前找,那麼就是穩定的。一般的書上都是從前往後找,所以一般當作是不穩定的。
1.陣列的大小是2的冪,這樣分下去始終可以被2整除。假設為2的k次方,即k=log2(n).
2.每次我們選擇的值剛好是中間值,這樣,陣列才可以被等分。
第一層遞迴,迴圈n次,第二層迴圈2*(n/2)......
所以共有n+2(n/2)+4(n/4)+......+n(n/n)=n+n+n+......+n=k*n=log2(n)*n
所以共有o(log2(n)*n)
其他的情況只會比這種情況差,最差的情況是每次選擇到的middle都是最小值或最大值,那麼他將變成交換法(由於使用了遞迴,情況更糟)。但是你認為這種情況發生的機率有多大?大多數情況下,快排總是最好的。
穩定性:
首先,排序演算法的穩定性大家應該都知道,通俗地講就是能保證排序前2個相等的數其在序列的前後位置順序和排序後它們兩個的前後位置順序相同。
其次,說一下穩定性的好處。排序演算法如果是穩定的,那麼從乙個鍵上排序,然後再從另乙個鍵上排序,第乙個鍵排序的結果可以為第二個鍵排序所用。基數排序就是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時是不會改變的。另外,如果排序演算法穩定,對基於比較的排序演算法而言,元素交換的次數可能會少一些。
(1)氣泡排序
氣泡排序就是把小的元素往前調或者把大的元素往後調,比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個元素相等,我想你是不會再無聊地把他們倆交換一下的,如果兩個相等的元素沒有相鄰,那麼即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前後順序並沒有改變,所以氣泡排序是一種穩定的排序演算法。
(2)選擇排序
選擇排序是給每個位置選擇當前元素最小的,比如給第乙個位置選擇最小的,在剩餘元素裡面給第二個元素選擇第二小的,依此類推,直到第n-1個元素,第n個元素不用選擇了,因為只剩下它乙個最大的元素了。那麼,在一趟選擇,如果當前元素比乙個元素小,而該小的元素又出現在乙個和當前元素相等的元素後面,那麼交換後穩定性就被破壞了。例如5 8 5 2 9,第一趟選擇第乙個5和2交換,第乙個5在第二個5的後面了。
(3)插入排序
插入排序是在乙個已經有序的小序列的基礎上,一次插入乙個元素。當然,剛開始這個有序的小序列只有1個元素,就是第乙個元素。比較是從有序序列的末尾開始,也就是想要插入的元素和已經有序的最大者開始比起,如果比它大則直接插入在其後面,否則一直往前找直到找到它該插入的位置。如果碰見乙個和插入元素相等的,那麼插入元素把想插入的元素放在相等元素的後面。所以,相等元素的前後順序沒有改變,從原無序序列出去的順序就是排好序後的順序,所以插排是穩定的。
(4)快速排序
快排有兩個方向,左邊的i下標一直往右走,當a[i]<=a[center_index],其中center_index是中樞元素的陣列下標,一般取為陣列的第0個元素,而右邊的j下標一直往右走,當a[j]>a[center_index]。如果i和j都走不動了,i<=j,交換a[i]和a[j],重複上面的過程,直到i>j。交換a[j]和a[center_index],完成一趟快速排序。在中樞元素和a[j]交換的時候,很有可能把前面的元素的穩定性打亂,比如序列5 3 3 4 3 8 9 10 11,現在中樞元素和3(第五個元素)交換就會把元素3的穩定性打亂。
(5)歸併排序
歸併排序是把序列遞迴地分成短序列,遞迴出口是短序列只有1個元素(認為直接有序)或者2個序列(1次比較和交換),然後把各個有序的段序列合併成乙個有序的長序列,不斷合併直到原序列全部排好序。可以發現,在1個或2個元素時,1個元素不會交換,2個元素如果大小相等也沒有人故意交換,這不會破壞穩定性。那麼,在短的有序序列合併的過程中,穩定是是否受到破壞?沒有,合併過程中我們可以保證如果兩個當前元素相等時,我們把處在前面的序列的元素儲存在結果序列的前面,這樣就保證了穩定性。
(6)基數排序
折半插入排序
希爾排序
快速排序
二叉樹排序
氣泡排序
選擇排序
堆排序#include
#include
#include
#include
//折半插入排序
入口引數:long* array:指向陣列的指標;long key:關鍵字;long start:開始索引;long end:結束索引
int halfsearch(long* array,long key,long start,long end)
void halfinssort(long* array/*陣列*/,long leng/*陣列長度*/)
array[pos]=temp;//放入適當的位置}}
}//希爾排序,引數解釋同上
void shellsort(long* array,long leng)
array[j+step]=temp;//小的數放到適當的位置
}step=step/2;//再找下乙個步長}}
//二叉樹排序
//1.陣列表示
/*如果恰好此樹是乙個從大到小的序列,則需要的樹空間為2的元素次方個儲存空間*/
/*空間的浪費太大,不划算*/
void binarytree(long* btree,/*排序的陣列*/long* array,/*原始陣列*/long leng/*陣列長度*/)
btree[parent]=array[i]; //找到正確的位置後插入。返回開始處再找;}}
void inorder(long* btree,/*樹的頭接點*/long pos,/*找到的索引*/long leng/*陣列長*/)
}//2.鍊錶表示
typedef struct node_node;
node* createtree(long* array,/*給定的元素*/long leng/*長度*/)
else
};if(leftflag==1)//在左子樹
left->left =newnode;
else//在右子樹
right->right =newnode;
}if(root!=null)
return root;
else
return null;
}void inorder(node* root)
//交換排序
//1.氣泡排序
void bubblesort(long* array,long leng)}}
}}//2.快速排序
//基本思想是找乙個關鍵字,小於它的放在它的左邊,大於的放在右邊;對兩邊的序列繼續排
void quicksort(long* array,long low,long high)
key=array[low];//一般以最小索引的數做關鍵字
scanup=low;
scandown=high;
dowhile(scandown!=scanup); //直到前後的掃瞄鍵在同一位置為關鍵字的地方
array[scanup]=key;
quicksort(array,low,scandown-1);//向前快排
quicksort(array,scanup+1,high);//向後快排
}/*選擇排序*/
//1.直接選擇排序
void selectsort(long* array,long leng)
}//2.堆排序
//基本思想:先由給出的關鍵字來建立乙個堆,然後用
void createheap(long* heap,/*陣列表示堆的指標*/long root/*頭接點的序號*/,long leng)
}heap[child/2]=temp; //節點放入適當的位置
}void heapsort(long* heap,long leng)
}
排序演算法小結
1 快速排序 quicksort 快速排序是乙個就地排序,分而治之,大規模遞迴的演算法。從本質上來說,它是歸併排序的就地版本。快速排序可以由下面四步組成。1 如果不多於1個資料,直接返回。2 一般選擇序列最左邊的值作為支點資料。3 將序列分成2部分,一部分都大於支點資料,另外一部分都小於支點資料。4...
排序演算法小結
1 歸併排序 3.區別與聯絡 遞迴是從未知推到已知,相當於把未知的東西壓入棧,等到可以算出結果了,就一步一步出棧。迭代是從已知到未知,從已知的東西一步一步推至目標。遞迴與迭代就好像一對逆元。遞迴的 更加清晰,但開銷更大,也更容易出錯,除錯較困難 而迭代的 編寫更困難,但速度和開銷較小。4.空間占用 ...
排序演算法小結
演算法過程 假設乙個無序的序列,該演算法將其分成兩部分,前一部分已經完成排序 有序,一開始時只有乙個元素 後一部分任然無序,將後面序列選擇第乙個插入到前面的有序序列,如此直到所有完全有序。複雜度 最簡單的即為,整個序列原來即有序,按照一種最 省事 的方式,我們僅需比較n 1次即可。最複雜的情況,應該...