選擇排序 總結

2022-03-14 06:45:32 字數 3384 閱讀 2808

選擇排序的基本思想:每趟從待排序的記錄中選出關鍵字最小的記錄,順序放在已排好序的子檔案的最後,直到全部記錄排序完畢。

常用的選擇排序方法有直接選擇排序和堆排序。

n個記錄的檔案的直接選擇排序可經過n-1趟直接選擇排序得到有序結果。

第1趟從r[0]~r[n-1]中選取最小值,與r[0]交換;

第2趟從r[1]~r[n-1]中選取最小值,與r[1]交換;

第i趟從r[i-1]~r[n-1]中選取最小值,與r[i-1]交換;

直接選擇排序和直接插入排序類似,都將資料分為有序區和無序區,所不同的是直接插入排序是將無序區的第乙個元素直接插入到有序區以形成乙個更大的有序區,而直接選擇排序是從無序區選擇乙個最小的元素直接放到有序區的最後。

給定一組資料[8 3 2 5]

第一次交換 82

2 3 8 5  

第二次交換 33

2 3 8 5

第三次交換   85

2 3 5 8

void selectsort(int *arr, int len)
}
temp = arr[i];			// 交換
arr[i] = arr[imin];
arr[imin] = temp;
}
}
直接選擇排序是乙個就地排序,但是直接選擇排序不是穩定的。直接選擇排序的平均時間複雜度是,而它的最壞情況時間複雜度也是

。參考:

堆可以視為一棵完全的二叉樹,完全二叉樹的乙個「優秀」的性質是,除了最底層之外,每一層都是滿的,這使得堆可以利用陣列來表示,每乙個結點對應陣列中的乙個元素。

陣列與堆之間的關係

二叉堆一般分為兩種:最大堆和最小堆。

堆中每個父結點的元素值都大於等於其孩子結點(如果存在),這樣的堆就是乙個最大堆。

結點與陣列索引關係

對於給定的某個結點的下標i,可以很容易的計算出這個結點的父結點、孩子結點的下標,而且計算公式很漂亮很簡約:

1)先將初始檔案r[1…n]建成乙個大根堆,此堆為初始的無序區

2)再將關鍵字最大的記錄r[1](即堆頂)和無序區的最後乙個記錄r[n]交換,由此得到新的無序區r[1..n-1]和有序區r[n],且滿足r[1…n-1].keys<=r[n].key

3)由於交換後新的根r[1]可能違反堆性質,故應將當前無序區r[1…n-1]調整為堆。

然後再次將r[1..n-1]中關鍵字最大的記錄r[1]和該區間的最後乙個記錄r[n-1]交換,由此得到新的無序區r[1..n-2]和有序區r[n-1..n],且仍滿足關係r[1…n-2].keys<=r[n-1…n].keys,同樣要將r[1..n-2]調整為堆。

直到無序區只有乙個元素為止。

既然是堆排序,自然需要先建立乙個堆,而建堆的核心內容是調整堆,使二叉樹滿足堆的定義(每個結點的值都不大於其父結點的值)。調整堆的過程應該從最後乙個非葉子結點開始,假設有陣列a=。那麼調整堆的過程如下圖,陣列下標從0開始,a[3]=5開始。分別與左孩子和右孩子比較大小,如果a[3]最大,則不用調整,否則和孩子中的值最大的那乙個交換位置,在圖1中是a[7]>a[3]>a[8],所以a[3]與a[7]對換,從圖1.1轉到圖1.2。

注意:使用最小堆排序後是遞減陣列,要得到遞增陣列,可以使用最大堆。

1、堆化陣列

如何對乙個資料進行堆化操作。要乙個個的從陣列中取出資料來建立堆嗎?不用,先看乙個陣列,如下圖:

很明顯,對葉子結點來說,可以認為它已經是乙個合法的堆,即20,60,65,4,49都 分別是乙個合法的堆。只要從a[4]=50開始向下調整堆就可以了。然後再取a[3]=30,a[2]=17,a[1]=12,a[0]=9分別做一次向下調整操作就可以了。

由於堆也是用陣列模擬的,故堆化陣列後,第一次將a[0]與a[n - 1]交換,再對a[0…n-2]重新恢復堆。第二次將a[0]與a[n – 2]交換,再對a[0…n - 3]重新恢復堆,重複這樣的操作直到a[0]與a[1]交換。由於每次都是將最大的資料併入到後面的有序區間,故操作完成後整個陣列就有序了。有點類似於直接選擇排序

/** 

功能:調整為最大堆
思路:
1、找到左右孩子中最大的值
2、判斷是否賦給父結點
*/
void adjustmaxheap(int a, int i, int n)
a[i] = temp;		                  // 儲存父結點的值,此時i是j的值,表示孩子的值
}
/**

功能:建立初始堆(最大堆)
思路:
1、要想將初始檔案r[1..n]調整為乙個大根堆,就必須將它
所對應的完全二叉樹中以每一結點為根的子樹都調整為堆。
2、顯然只有乙個結點的樹是堆,而在完全二叉樹中,所有序號i>[n/2](向下取整)的
結點都是葉子,因此以這些結點為根的子樹均已是堆。
3、我們只需依次將以序號為[n/2],[n/2]-1,...1的結點作為根的子樹都調整為堆即可。
4、由於c語言中陣列下標從0開始,因此,第3點的序號改為[n/2]-1,[n/2]-2,...0。
*/
void makemaxheap(int a, int n)
/**

1、建立初始堆
2、每一趟最後乙個數都與a[0]交換,並重新調整堆,
使其保持堆的特性。
*/
void maxheapsort(int a, int n)
}
堆排序是不穩定,但是它的平均時間複雜度和最差情況時間複雜度都是o(nlogn)。

排序總結 選擇排序

在無序陣列中選出最小的與當前最小的值進行交換 具體步驟 如將第乙個元素看做此時最小值,從第二個元素開始依次向後遍歷找出最小的元素進行交換,此時第乙個位置放置的元素一定是最小的值,在從剩下的無序陣列中找出最小的與第二個元素進行交換,依次往下直到無序陣列只剩下乙個元素為止 public static v...

直接選擇排序總結

1 選擇排序基本思想 每一趟從待排序的記錄中找出最小記錄,順序放在已排好序的子檔案最後,直到全部記錄排序完畢。2 直接選擇排序基本思想 n個記錄的檔案的直接選擇排序可經過n 1趟直接選擇排序得到有序結果 初始狀態 無序區為r 1.n 有序區為空。第1趟排序 在無序區r 1.n 中選出關鍵字最小的記錄...

選擇類排序總結

選擇類排序總結 所謂選擇類排序的思想就是 從陣列的中選出最大或最小的,通過多次選擇最後達到排序的目的 首先是簡單選擇排序 思想 每趟掃瞄中,選出最小的數字放在最前面,然後從第二個數字開始掃瞄,直到只剩下最後乙個數不需要掃瞄 void easyselect sort int a,int n 第三步就是...