数据结构——第七讲、排序

简单排序

1、冒泡排序

void bulle_sort(ElementType A[], int N){
	for(int p = N-1; p >= 0; p--){
		int flag = 0;
		for(int i = 0; i < p; i++){
			if(A[i] > A[i+1]){
				swap(A[i], A[i+1]);
				int flag = 1;
			}
		}
		if(flag == 0) break;
	}
}

2、插入排序

void insertion_sort(ElementType A[], int N){
	for(int p = 1; p < N; p++){
		tem = A[p];
		//这里的i > 0必须放在前面,否则有可能会出现下标越界的错误。
		for(int i = p; i >= 1 && A[i-1] > tem; i--)
			A[i] = A[i-1];
		A[i] = tem;
	}
}

时间复杂度下界

定理: 任意N个不同元素组成的序列,平均有N(N-1)/4个逆序对。
  交换两个相邻元素正好消去一个逆序对。
定理: 任何仅以交换相邻两元素来排序的算法,其平均时间复杂度下届为 N的平方 级。

3、希尔排序

void shell_sort(ElementType A[], int N){
	for(int D = N/2; D > 0; D /= 2){
		//对每一个D做一次选择排序
		for(p = D; p < N; p++){
			tem = A[p];
			for(int i = p; i >= D && A[i-D] > tem; i -= D)
				A[i] = A[i-D];
			A[i] = tem;
		}
	}
}

4、选择排序

void selection_sort(ElementType A[], int N){
	for(int i = 0; i < N; i++){
		//从i到N-1中找到最小值
		MinPosition = ScanForMin(A, i, N-1);
		Swap(A[i], A[MinPosition]);
	}
}

5、堆排序

void heap_sort(ElementType A[], int N){
	//构造最大堆,其中PercDown是一个"向下过滤函数",i=N/2表示i为最后一个节点的父节点。
	for(int i = N/2; i >= 0; i--)
		//此函数就是将一个堆调整为最大堆的函数
		//第二个参数表示以此节点为根节点调整最大堆,第三个参数表示这个最大堆一共有几个元素。
		PercDown(A, i, N);
	for(int i = N-1; i>0; i--){
		Swap(A[0], A[i]);
		PercDown(A, 0, i);
	}
}

6、归并排序

// L 左边起始位置,R 右边起始位置, RightEnd 右边终点位置
void merge(ElementType A[], ElementType TmpA[], int L, int R, int RightEnd){
	//假设左右两列紧挨着
	int LeftEnd = R - 1;
	Tmp = L;
	ElementNum = RightEnd - L + 1;
	while( L <= LeftEnd && R <= RightEnd ){
		if( A[L] < A[R] )
			TmpA[Tmp++] = A[L++];
		else
			TmpA[Tmp++] = A[R++];
	}
	while( L <= LeftEnd )
		TmpA[Tmp++] = A[L++];
	while( R <= RightEnd )
		TmpA[Tmp++] = A[R++];
	for( int i = 0; i < ElementNum; i++, RightEnd--)
		A[RightEnd] = TmpA[RightEnd];
}
//递归的调用merge方法,完成归并排序
void Msort(ElementType A[], ElementType TmpA[], int L, int RightEnd){
	int center = (RightEnd + L) / 2;
	if(L < RightEnd){
		Msort(A, TmpA, L, center);
		Msort(A, TmpA, center+1, RightEnd);
		merge(A, TmpA, L, center+1, RightEnd);
	}
}
//统一排序的接口
void merge_sort(ElementType A[], int N){
	ElementType *TmpA;
	TmpA = (ElementType)malloc(N * sizeof(ElementType));
	if(TmpA != NULL){
		Msort(A, TmpA, 0, N-1);
		free(TmpA);
	}else
		Error("空间不足");
}

非递归算法

void merge_pass(ElementType A[], ElementType TmpA[], int N, int length){
	//这一步只排前面成对的,最后一段剩下。
	for(int i = 0; i < N - 2*length; i += 2*length )
		//这个merge1比起merge来,不把最后的结果复制到A中,而是保留在TmpA中
		merge1(A, TmpA, i, i+length, i + 2*length-1);
	if( i + length < N)
		merge1(A, TmpA, i, i+length, N-1);
	else
		for(int j = i; j < N; j++) TmpA[j] = A[j];
}
//统一排序的接口
void merge_sort(ElementType A[], int N){
	int length = 1;
	ElementType *TmpA;
	TmpA = (ElementType)malloc(N * sizeof(ElementType));
	if(TmpA != NULL){
		while(length < N){
			merge_pass(A, TmpA, N, length);
			length *= 2;
			merge_pass(TmpA, A, N, length);
			length *= 2;
		}
		free(TmpA);
	}else
		Error("空间不足");
}

7、快速排序

  快速排序适合大规模数据,如果数据规模小,可以不做快排,直接调用简单排序解决问题。

//第一步,选主元,取头、中、尾的中位数
ElementType Median3(ElementType A[], int Left, int Right){
	int Center = ( Left + Right ) / 2;
	if(A[Left] > A[Center])
		Swap(A[Left], A[Center]);
	if(A[Left] > A[Right])
		Swap(A[Left], A[Right]);
	if(A[Center] > A[Right])
		Swap(A[Center], A[Right]);
	Swap(A[Center], A[Right-1]);
	//返回主元值
	return A[Right-1];
}
//第二步,递归的排序
void QuickSort(ElementType A[], int Left, int Right){
	if( Cottoff <= Right - Left ){
		//调整好主元位置。
		ElementType Pivot = Median3(A, Left, Right);
		//设置好指针位置
		int i = Left;
		int j = Right-1;
		for(;;){
			while(A[++i] < Pivot){}
			while(A[--j] > Pivot){}
			if( i < j )
				Swap(A[i], A[j]);
			else
				break;
		}
		Swap(A[i], A[Right-1]);
		QuickSort(A, Left, i-1);
		QuickSort(A, i+1, Right);
	}
	else
		insertion_sort(A + Left, Right - Left + 1);
}
//第三步,封装
void quick_sort(ElementType A[], int N){
	QuickSort(A, 0, N-1);
}

8、其他排序

表排序:
  当一个元素非常大,不能忽略元素交换的时间的时候,需要使用表排序,一种间接排序,会得出一个下标的顺序,不去改变元素本身的顺序。
基数排序:
  适用于多关键字排序,按照不同的关键字多次利用桶排序完成多关键字排序。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值