选择排序的基本思想是:每一趟在n-i-1(i=1,2,...,n-1)个记录中选取关键字最小的记录作为有序序列的第i个记录。我们主要学习的是简单选择排序、堆排序。
1、简单选择排序
算法思想:①一趟排序操作为:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i个交换。
②再令i从1至n-1,进行n-1趟选择操作。
算法实现:
C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
|
#include
void
SelectSort(
int
arr[],
int
len) {
int
i, j;
int
min;
int
tmp;
for
(
int
i =
0
; i < len -
1
; ++i) { min = i;
for
(j = i +
1
; j < len; ++j) {
if
(arr[j] < arr[min]) { min = j; } }
if
(min != i) { tmp = arr[min]; arr[min] = arr[i]; arr[i] = tmp; } } }
int
main() {
int
arr[] = {
1
,
5
,
6
,
3
,
4
,
2
,
8
,
6
,
1
};
int
len =
sizeof
(arr) /
sizeof
(arr[
0
]); SelectSort(arr, len);
return
0
; }
|
时间复杂度:比较操作为n(n-1)+(n-1)次,移动操作最多为3(n-1)+n+(n(n-1)/2)次,即时间复杂度为O(n^2).
空间复杂度:临时变量只有min 和 tmp,即空间复杂度为o(1).
稳定性:如{7,5,5,3,2,8},影响5的前后顺序。
2.堆排序
由于堆排序采用“堆”这种数据结构,所以我们可以用大根堆、小根堆来实现。这里我们用大根堆来说明。
算法思想:①
先将初始数据R[1..n]建成一个大根堆,此堆为初始的无序区。
②
再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区 R[1..n-1]和有序区R[n]
③
由于交换后新的根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]调整为堆 ...... 直到无序区只有一个元素。
算法实现:
C++ Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
|
void
HeapAdjust(
int
*arr,
int
i,
int
length) //调整堆 {
for
(
int
j =
2
* i; j <= len; j =
2
* j) { if(j < len && arr[j] < arr[j +
1
] ) { j++; }
if
(arr[i] > arr[j])
break
; arr[
0
] = arr[i]; arr[i] = arr[j]; arr[j] = arr[
0
]; i = j; } }
void
HeapSort(
int
*arr,
int
len) //堆排序 {
for
(
int
i = len /
2
; i >
0
; i--) //反复调整建立堆 { HeapAdjust(arr, i, len); }
for
(
int
j = len; j >
0
; j--) //交换堆顶元素与无序区最后一个元素 { arr[
0
] = arr[
1
]; arr[
1
] = arr[j]; arr[j] = arr[
0
]; HeapAdjust(arr,
1
, j -
1
); } }
|
时间复杂度:因为堆排序函数是先反复调整建立堆(,然后每次选出堆顶元素为有序区元素并调整堆。在建堆时为o(n);调整堆时为o(lgn),调用n-1次,即时间复杂度为o(nlgn).
空间复杂度:o(1)。
稳定性:不稳定。