排序是在程序開發中常用的操作,也是個大公司面試的時候檢驗一個人編程能力的一個必考題,排序就是涉及到了算法了,今天下午就想着來搞一下排序的算法,算是對其有一個初步的瞭解吧,後天期中考了,掛科可就不是排序算法能夠解決的問題了。
衡量一個算法優劣的標準:
1.時間複雜度,完成這個任務,算法所需要的時間。
2.空間複雜度,完成該任務,算法所需要的佔用的內存空間,或者是所需要的外部輔助空間。
3.穩定性,完成任務後,對原始數據的影響大不大,會不會產生了一些不必要的操作,導致了原始數據發生了錯誤。
現在的排序方式分爲兩種:1.內部排序2.外部排序
內部排序就是整個排序操作都在內存中執行不藉助於外部,外部排序就是需要藉助外部的存儲,大多是數據量比較大的一些排序,對於外部排序常用的方式就是多路歸併操作,將原始文件分成多個可以一次性裝進內存的子文件,執行排序,排序後,將其輸出到外部程序中。
我們所說的排序大多指的是內部排序,內部排序分爲以下幾類:選擇排序(直接選擇排序,堆排序),交換排序(冒泡排序,快速排序),插入排序(直接插入排序,折半插入排序,Sheel排序),歸併排序,桶式排序,基數排序。
選擇排序
1.直接選擇排序
//直接選擇排序
public int[] sort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
int max = a[i];
for (int j = i + 1; j < a.length; j++) {
if (a[j] > max) {
max = a[j];
a[j] = a[i];
a[i] = max;
}
}
}
return a;
}
思路:兩個嵌套的for循環,通過第一個循環找到第一個元素,通過一個值記錄這個元素,然後進入下一個循環,通過這個循環找到該數組中當前元素值要大的數,然後將兩者的值進行交換。上面的排序中當找出來符合值之後要進行多次值的交換,比較影響程序性能的,下面這種通過記錄其下標值來對較大的值做一個記錄,然後最後再對其進行交換,如果數據大的話,明顯的可以提升程序的性能。
public int[] sort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
int index = i;
for (int j = i + 1; j < a.length; j++) {
if (a[j] > a[index]) {
index = j;
}
}
if(index != i)
{
// 不借助第三變量將連個數的值進行交換
a[i] = a[index]+a[i];
a[index] = a[i]- a[index];
a[i] = a[i] - a[index];
}
}
return a;
}
2.堆排序
堆排序,首先就是要建堆,堆在這裏又分爲大頂堆和小頂堆,根據堆,堆在本質上就是一個二叉樹,大頂堆就是二叉樹的根節點是樹中最大的值,小頂堆就是根節點爲最小的二叉樹,利用堆進行排序的時候,首先是將所有數據建堆,將最大數或者最小數選擇出來,然後放在所有數據的最後面,然後將剩餘的數據執行上一次操作。
public void buildHeap(int [] a){
for(int i = 0;i<a.length-1;i++){
buildMaxHeap(a,a.length-1-i);
a[0] = a[0]+a[a.length-1-i];
a[a.length-1-i] =a[0]-a[a.length-1-i];
a[0]=a[0]-a[a.length-1-i];
}
}
public void buildMaxHeap (int []a,int lastIndex){
for(int i = (lastIndex-1)/2 ; i >= 0 ; i--){
int k = i;
while(k*2+1 <= lastIndex){
int biggerIndex = 2*k+1;
if(biggerIndex<lastIndex){
if(a[biggerIndex]<a[biggerIndex+1]){
biggerIndex++;
}
}
if(a[k]>a[biggerIndex]){
a[k] = a[k]+a[biggerIndex];
a[biggerIndex] = a[k] - a[biggerIndex];
a[k] = a[k]-a[biggerIndex];
}
else
break;
}
}
}
對原來的數組進行抽象化,將其抽象成一棵二叉樹,數組中的首位元素是二叉樹的根結點,首先我們找到該數組的最後一位元素的下標,然後建立大頂堆,找到最後一個元素的父結點,判斷左右結點的大小,然後記錄下數值較大的數的座標,然後將其和其父節點進行數值上的交換,然後繼續向和其父節點處在同一層的元素的大小判斷,最中產生
了一個大頂堆,然後我們將這個頂端的值保存在數組的最後一個元素的位置,然後將之前的記錄的最後一個位置座標向前移動一位,然後接着進行循環。