408-数据结构-排序-简单选择&堆排序

简单选择排序

算法思想:每一次找到序列中最大值的位置,然后将其与最后一个交换,长度为n的序列完成n-1趟就能够实现从小到大排序。

空间复杂度:O(1)
时间复杂度:稳定O(n2)
稳定性:不稳定
可以用于链表

void selectSort(int a[], int length){
	for (int i = length -1 ; i >= 0 ; i--){
		int maxPos = 0;
		for (int j = 1 ; j <= i ; j ++)
			if (a[j] > a[maxPos]){
				maxPos = j;
			}
		int tem = a[i];
		a[i] = a[maxPos];
		a[maxPos] = tem;
	}
	return ;
}

堆排序

堆:
满足根大于左右子树,称大根堆,完成递增排序;
满足根小于左右子树,称小根堆,完成递减排序。

堆可以看作是完全二叉树,同时算法代码实现用的也是二叉树顺序存储结构。
即根a[i],对应左孩子a[2i],右孩子a[2i+1]

堆排序思想就是通过堆来获取最大或者最小值,然后放在最后,视作已经排序元素,不计入堆中,然后再进行堆获取最值。最后就能够完成排序。

所以堆排序最重要的问题就有三个:

  1. 怎么通过堆获取最值,这个简单,根据定义,根结点就是最值,拿出来就行。
  2. 怎么构造堆?
  3. 与平衡二叉树类似,如果进行结点删除,怎么维护堆?

构造堆,以大根堆为例。
从定义出发只要保证根这个位置,比他的子树都大就行。完全二叉树可以知道如果位置<=n/2向下取整那么这个结点一定不是叶子结点,所以就从这里开始判断。
如果这个根比他的孩子小,就需要将他的孩子换上来。当然这里得选择两个孩子最大的那个换上来。换完之后还并没有结束,因为这个根也许比他的孙子还要小,所以需要一直往下判断,直到这个根比他的左右孩子都要大为止。这个过程是堆排序中最重要的过程。
这个过程还有一个优化的点,类似插入排序不断后移覆盖的思想,可以将根结点放在一个变量里,然后每一次如果需要将根结点替换,直接将其覆盖,而不是进行交换,需要跟根结点判断改为跟变量判断。然后最后将变量覆盖到最后根所在位置即可。
对于每一个非叶结点进行上述操作那么就可以获得一个堆。

构造完堆,就需要将其放到最后,也就是可以直接将对顶与堆的最后一个结点交换,然后视最后一个结点已经不在堆的考虑范围之内就行。然后对根再进行一个上述的一步维护操作就可以的到n-1个结点的堆。然后循环你懂的。

空间复杂度:O(1)
时间复杂度:O(nlogn)。其中建堆操作需要O(n)。维护堆的操作最多4logn也就是在O(logn)。
稳定性:不稳定

算法优点,每一次获取最值时间复杂度为O(logn)

额外补充:
如果在堆中插入一个元素,以大根堆为例,可以将插入元素放在最后,然后判断他的父结点是否比他小,如果比他小他俩换位,一直向上这样判断。
如果需要在堆中删除一个元素,让最后一个结点代替他的位置,然后对这个位置做一次维护操作就行。

void opt(int a[], int length, int pos){
	int tem = pos;
	int j;
	for (int i = pos ; i < length; i >>= 1){
		j = pos << 1;
		if (j < length-1 && a[j+1] > a[j])
			j++;
		if (tem >= a[j])
			break;
		a[i] = a[j];
	}
	a[j] = tem;
	return ;
}

void buildHeap(int a[], int length){
	for (int i = (length-1)/2  ; i > 0 ; i--){
		opt(a, length, i);
	}
}

void HeapSort(int a[], int length){
	buildHeap(a, length);
	for (int i = length-1 ; i > 0; i--){
		int a[0] = a[1];
		a[1] = a[i];
		a[i] = a[0];
		opt(a, length, 0);
	}
}

归并排序

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值