基本算法——排序算法

一、 插入排序

InsertSort(A, p, q)
1 for i <- p+1 to q
2 	do x <- A[i]
3 		for j <- i-1 to p
4 			do if A[j] > x
5 				 then A[j+1] <- A[j]
6 		A[j+1] <- x

算法复杂度:O(n^2)


折半插入排序:总得算法复杂度没变,但是查找插入位置(比较)的时间减少了。算法复杂度:O(n^2)。

BInsertSort(SqList *L)
{
	for(int i = 1; i < L.length(); ++i)
	{
		int low = 0, high = i-1;
		int x = L[i];
		while(low <= high)
		{
			int m = (low + high)/2;
			if(x < L[m]) high = m-1;
			else low = m+1;
		}
		for(int j = i-1; j >= high + 1; j--)
			L[j+1] = L[j]
		L[high+1] = x;
	}
}


二、 希尔排序

ShellInsert(SqList &L, int dk)
{
	for(int i = dk+1; i <= L.length(); ++i)
	{
		int x = L[i];
		int j = i-dk;
		while(j > 0 && L[j] > x) L[j+dk] = L[j];
		L[j+dk] = x;
	}
}

ShellSort(SqList &L, int delt[])
{
	for(int i = 1; i < delt[0]; ++i)
		ShellInsert(L, delt[i]);
}

希尔排序的复杂度难以分析。


三、 快速排序

int Partition1(A, p, r)
{
	int x = A[r];
	int i = p-1;
	for(int j = p; j < r; ++j)
		if(A[j] < x){
			int tmp = A[++i];
			A[i] = A[j];
			A[j] = tmp;
		}
	A[r] = A[++i];
	A[i] = x;
	return i;
}

int Partition2(A, low, high)
{
	int x = A[low];
	while(low < high)
	{
		while(low < high && A[high] >= x)--high;
		A[low] = A[high];
		while(low < high && A[low] <= x) ++low;
		A[high] = A[low];
	}
	A[low] = x;
	return low;
}


int QuickSort(A, low, high)
{
	if(low < high)
	{
		int m = Partition(A, low, high);
		QuickSrot(A, low, m-1);
		QuickSort(A, m+1, high);
	}
}

快速排序的平均时间复杂度为O(nlongn),最坏情况下复杂度为O(n^2)


四、选择排序和堆排序

1. 简单选择排序

void SelectSort(A)
{
	for(int i = 0; i < A.length(); ++i)
	{
		int j = SelectMin(A, i);
		if(j != i)
		{
			int tmp = A[i];
			A[i] = A[j];
			A[j] = tmp;
		}
	}
}
简单选择排序的时间复杂度为O(n^2)

2. 树形选择排序:

需要较多的额外空间,与最大值进行比较等多余的计算。


3. 堆排序

//已知H[s..m]除H[s]外,都满足(大顶)堆的定义,将H[s...m]调整,使之满足堆的定义
HeapAdjust(H, s, m)
{
	int key = H[s];
	int i = s;
	for(int j = s*2; j <= m; j *= 2)
	{
		if(j < m && H[j] < H[j+1])++j
		if(key >= H[j])break;
		H[i] = H[j];
		i = j;
	}
	H[i] = key;
}


HeapSort(H)
{
	for(int i = H.length/2; i > 0; --i)
		HeapAdjust(H, i, H.length);
	for(int i = H.length; i > 0; --i)
	{
		int tmp = H[i];
		H[i] = H[1];
		H[1] = tmp;
		HeapAdjust(H, 1, i-1);
	}
}
算法的时间复杂度为:O(nlogn),即使在 最坏情况下堆排序的 时间复杂度也为O(nlogn),仅需要一个辅助空间。

五、 归并排序

void Merge(int A[], int B[], int &C[])
{
	for(int k = 0, i = 0, j = 0; i < A.length && j < B.length; ++k)
	{
		if(A[i] <= B[j]) C[k] = A[i++];
		else C[k] = B[j++];
	}
	while(i < A.length)C[k++] = A[i++];
	while(j < B.length)C[k++] = A[j++];
}

void MergeSort(int A[], int &C[], int m, int n)
{
	if(m == n) C[m] = A[m];
	else{
		int mid = (m+n)/2;
		MSort(A, C1, m, mid);
		MSort(A, C2, mid+1, n);
		Merge(C1,C2, C);
	}
}

归并排序时间复杂度为O(nlogn),空间复杂度为O(n).



六、 基数排序
基数排序不需要关键字的比较。

1. 计数排序

  1. Count-Sort(A, B, k)  
  2. for i <-- 0 to k  
  3. 2   do C[i] <-- 0  
  4. for i <-- 1 to length[A]  
  5. 4   do C[A[i]] <-- C[A[i]] + 1  
  6. for i <-- 1 to k  
  7. 6   do C[i] <-- C[i-1] + C[i]  
  8. for j <-- length[A] downto 1  
  9. 8   do B[C[A[j]]] <-- A[j]  
  10. 9       C[A[j]] <-- C[A[j]] - 1  

 计数排序时间代价:Θ(k+n), 实践中当k=O(n)时,运行时间为O(n)。

2. 基数排序

  1. Radix-Sort(A, d)  
  2. for i <-- 1 to d  
  3. 2   do use a stable sort to sort array A on digit i 

七、 内部排序算法比较

下面是一个总的表格,大致总结了我们常见的所有的排序算法的特点。

排序法平均时间最差情形稳定度额外空间备注
冒泡O(n2)    O(n2)稳定O(1)n小时较好
交换    O(n2)    O(n2)不稳定O(1)n小时较好
选择O(n2)O(n2)不稳定O(1)n小时较好
插入O(n2)O(n2)稳定O(1)大部分已排序时较好
基数O(logRB)O(logRB)稳定O(n)

B是真数(0-9),

R是基数(个十百)

ShellO(nlogn)O(ns) 1<s<2不稳定O(1)s是所选分组
快速O(nlogn)O(n2)不稳定O(nlogn)n大时较好
归并O(nlogn)O(nlogn)稳定O(1)n大时较好
O(nlogn)O(nlogn)不稳定O(1)n大时较好




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值