基本算法(下)
一、选择排序
选择排序过程:
算法伪代码如下:
Input:A[1..n]
Output:已排好序的A[1...n]
for i = 1 to n:
k = i//记录位置
for j = i+1 to n://从后面的找最小
if A[j] < A[k]:
k = j//记录位置
t = A[i]//交换
A[i] = A[k]
A[k] = t
对于长度为n的数组,算法的比较次数为:(n-1)+(n-2)+(n-3)+…+1=n(n-1)/2;算法的元素赋值次数为:0~3(n-1),因为在交换元素的时候要赋值三次;算法的时间复杂度为:O( n 2 n^2 n2)。
递归实现:
Input:A[1..n]
Output:已排好序的A[1...n]
sort(i)
def sort(i):
if i < n :
k = i//记录位置
for j = i+1 to n://从后面的找最小
if A[j] < A[k]:
k = j//记录位置
t = A[i]//交换
A[i] = A[k]
A[k] = t
sort(i+1)
二、插入排序
插入排序过程:
整体思路:
在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。
但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。
算法伪代码如下:
Input:A[1..n]
Output:已排好序的A[1...n]
for i = 2 to n:
x = A[i]//每次前k个数都是有序的
j = i - 1
while(A[j]>x & j>0)://找谁比x小
A[j+1] = A[j]
j = j - 1
A[j+1] = x
对于长度为n的数组,算法的比较次数介于n-1~n*(n-1)/2之间,分别对应升序和降序的情况;算法的赋值次数为比较次数+n-1,即每次比较后的移动操作都要对元素进行赋值,最后插入的过程也要进行赋值。
算法的时间复杂度:最坏情况下为O(N*N),此时待排序列为逆序,或者说接近逆序;最好情况下为O(N),此时待排序列为升序,或者说接近升序。
递归实现:
Input:A[1..n]
Output:已排好序的A[1...n]
sort(n)
def sort(i):
if i > 0 :
sort(i-1)
x = A[i]//每次前k个数都是有序的
j = i - 1
while(A[j]>x & j>0)://找谁比x小
A[j+1] = A[j]
j = j - 1
A[j+1] = x
三、归并排序(Bottom-Up Merge Sorting)
算法伪代码如下:
Input:A[1..n]
Output:升序排列的A[1..n]
t = 1
while t < n://将前面的序列两两合并成大小为t的序列
s = t//sequence size
t = 2s
i = 0
MERGE(A,i+1,i+s,i+t)//调用排列两个有序表的函数
i = i+t
if i+s < n //判断是否与最后的元素合并
MERGE(A,i+1,i+s,n)
在合并有序表时,当两个数组的大小分别为m和n且m≤n时,算法的比较次数为介于m与m+n-1之间。元素的赋值次数即为2(m+n)(注意输入输出和辅助数组)。
故对于在while中的第j次迭代,两个大小为
2
(
j
−
1
)
2^{(j-1)}
2(j−1)的子序列合并操作共有
n
/
2
j
n/2^j
n/2j次,综上第j次迭代中元素比较次数在
(
n
/
2
j
)
2
j
−
1
(n/2^j)2^{j-1}
(n/2j)2j−1到
(
n
/
2
j
)
(
2
j
−
1
+
2
j
−
1
−
1
)
(n/2^j)(2^{j-1}+2^{j-1}-1)
(n/2j)(2j−1+2j−1−1)次。设k=logn,则元素最少比较次数:
对于元素赋值次数,每次执行while都要进行2n次赋值,共进行2nlogn次。
归并排序算法每次将序列折半分组,共需要logn轮,因此归并排序算法的时间复杂度是O(nlogn)。
四、基数排序(Radix Sort)
输入:{53, 3, 542, 748, 14, 214}
第一次迭代:542,53,3,14,214,748
第二次迭代:3,14,214,542,748,53
第三次迭代:3,14,53,214,542,748
算法伪代码如下:
Input:A linked list of numbers L = {a1,a2,a3,...,ak} and the number of digits k
Output:升序表L
for i = 1 to k:
prepare 10 empty list L0,...,L9
for j in L:
append j to Li
L = L0
for k = 1 to 9:
append Lk to L
return L
可以确定基数排序的时间复杂度一定是线性级别的,但是虽然是线性级别的,但是有一个系数的,这个系数就是最大元素的位数K,所以时间复杂度应该是O(n*k),如果k是常数,则为O(n);空间复杂度为:O(10×n)= O(n)。