排序算法——选择排序(简单选择,堆排序)

简单选择排序

思想:

从待排序列中选择最小的元素放在第一位,然后每趟都从待排序列中选最小的元素,放在已排序的序列末端。

public static int[] selectSort(int[] arr){
	for(int i = 0; i < arr.length - 1; i++){ //这里-1是因为第一个元素不与自己比较
		int minIndex = i;
		for(int j = i + 1; j < arr.length; j++){  //j = i+1 表示每次都从剩下序列的第一个元素开始找
			if(arr[j] < arr[minIndex])        //若改为 > 号,则排序出的序列从大到小
				minIndex = j;     // 找到最小元素的索引
		}
		swap(arr,i,minIndex);
	}
	return arr;
}

复杂度分析:

无论序列怎么样,都要遍历两轮序列,所以最好,最坏,平均复杂度都是O(n^2)。

稳定性:

该排序算法改变相同元素的相对位置,所以是不稳定的。


堆排序

思想:

1.将无需序列构造成一个大顶堆(又叫大根堆,若想要排出从大到小的序列,则需要构造小顶堆),构造大顶堆从最后一个非叶子结点开始(若该二叉树从0开始编号,最后一个非叶子结点应是arr.length / 2 - 1,读者可自行验证)
2.将堆顶元素(构造完大顶堆后,堆顶元素总是当前二叉树的最大数)与最后一个元素交换(等价于把当前的最大数沉底)
3. 此时的子序列可能不满足大顶堆的要求了,就需要调整二叉树使之满足大顶堆要求。然后重复执行2,3,直至整个序列有序

注:若该二叉树从0开始编号,假设父结点编号为i,则左孩子为2i+1,右孩子为2i+2。

大顶堆要求: arr[i] > arr[2i+1] && arr[i] > arr[2i+2] (小顶堆要求: arr[i] < arr[2i+1] && arr[i] < arr[2i+2] )

该算法强烈建议读者自行Debug一遍,跟踪各个变量值的变化,并同时在纸上演算一遍排序全部过程,才会对各个变量的取值有较深的理解。

public static int[] heapSort(int[] arr){
	buildMaxHeap(arr);    // 构造大顶堆
	//i > 0 而不是 >= 的原因在于下一句:堆顶元素不用与自己交换
	for(int i = arr.length - 1; i > 0; i--){  //arr.length - 1是初始二叉树的最后一个元素
		swap(arr,0,i);  //将堆顶元素与最后一个元素交换
		adjustHeap(arr,0,i);   //调整二叉树
	}
	return arr;
}
public static void buildMaxHeap(int[] arr){
	//i >= 0 而不是 > 的原因在于:堆顶元素所在的最小二叉树(仅含堆顶元素及其两个孩子)也可能不满足大顶堆要求,也需要调整
	for(int i = arr.length / 2 - 1; i >= 0; i--){
		adjustHeap(arr,i,arr.length);
	}
}
public static void adjustHeap(int[] arr, int i, int length){
	//编号为i的结点为当点最小二叉树的父结点
	int father = arr[i];
	for(int child = 2 * i + 1; child < length; child = 2 * child + 1){
		//第一个条件保证右孩子存在,第二个条件保证右孩子比左孩子大
		if(child + 1 < length && arr[child] < arr[child + 1])
		//将孩子指针指向右孩子
			child++;
		if(father < arr[child]){
			//如果孩子比父亲大,则交换父亲孩子,形成当前大根堆
			swap(arr,i,child);
			//可能当前孩子还有其子树,需将当前父亲指针指向当前孩子,使之成为其孩子的父亲,进行当前孩子的子树的大根堆调整
			i = child;
		}else
			break;

		//将两个if判断改为if(child + 1 < length && arr[child] > arr[child + 1]) 和 if(father > arr[child]),
		//即为构造小顶堆,构造从大到小的序列
	}
} 

复杂度分析:

平均,最好,最坏复杂度均为O(nlogn)。

稳定性:

该排序算法改变相同元素的相对位置,所以是不稳定的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值