Java排序算法总结之(三)——选择排序(简单选择排序、堆排序)

排序方法可以分为两种:内部排序 和 外部排序

内部排序的方法很多,常用的大致可以分为:

  1. 插入排序(直接插入排序、折半插入排序、希尔排序)
  2. 交换排序(冒泡排序、快速排序)
  3. 选择排序(简单选择排序、堆排序)
  4. 归并排序
  5. 基数排序

选择排序

1.简单选择排序

基本思想:对数列的 n 个元素进行比较,选出最小(或者最大)的元素,与起始位置的值交换,再从余下的数据中找到最小(最大)值,放在已排序部分的末尾,直到排序完毕。

示例:选择排序的示例动画。红色表示当前最小值,黄色表示已排序序列,蓝色表示当前位置。

            

Java代码:(注意与冒泡排序的区别)

public class SelectSort {
	public static int[] sort(int[] s) {
		for (int i = 0; i < s.length - 1; i++) {
			for (int j = i + 1; j < s.length; j++) {
				if (s[i] > s[j]) {
					int temp = s[i];
					s[i] = s[j];
					s[j] = temp;
				}
			}
		}
		return s;
	}
}
效率分析:

交换操作介于0和(n-1)次之间

选择排序的比较操作为n(n-1)/2次之间

选择排序的赋值操作介于0和3(n-1)次之间。总的时间复杂度为O(n^2)
稳定性:true,相等的值的相对位置不会发生改变。

2.堆排序

堆排序(Heapsort)是指利用 堆 这种数据结构所设计的一种排序算法。
堆 分为最大堆 和 最小堆,定义为子结点的键值或索引总是小于(或者大于)它的父节点
通常堆是通过一维数组来实现的。在Java中,数组起始位置为0,访问结点的计算方法为:
  • 父节点i的左子节点在位置(2*i+1);
  • 父节点i的右子节点在位置(2*i+2);
  • 子节点i的父节点在位置floor((i-1)/2);
排序常用最大堆来进行。
堆可以用完全二叉树来表示,又称二叉堆。任何一个数组都可以用堆来表示
         
使用堆排序,我们需要做三件事:
                    

  1. 创建最大堆:对数组中所有数据进行重排,使其满足最大堆的定义;
  2. 最大堆调整:创建最大堆时需要随时对已排好的最大堆进行重排,
  3. 堆排序:移除位于第一个数据的根节点,将最后的元素补到第一位,然后再进行调整
public class HeapSort {
	public static void buildHeap(int[] s) {
		// 叶子结点可以看成一个堆,故建堆从最后一个父节点开始
		int startIndex = getParentIndex(s.length - 1);
		// 循环添加结点,每添加一个,就要对当前堆进行调整,使其满足最大堆
		for (int index = startIndex; index >= 0; index--) {
			maxHeapAdjust(s, s.length, index);
		}
	}

	/**
	 * 最大堆调整函数
	 * 
	 * @param s 
	 * @param heapSize 
	 * @param parentIndex 
	 */
	private static void maxHeapAdjust(int[] s, int heapSize, int parentIndex) {
		// 计算传入结点索引的左右子结点
		int leftChildIndex = getLeftChildIndex(parentIndex);
		int rightChildIndex = getRightChildIndex(parentIndex);
		// 当前结点与左右结点比较,得到对应最大值的索引
		int max = parentIndex;
		if (leftChildIndex < heapSize && s[max] < s[leftChildIndex]) {
			max = leftChildIndex;
		}
		if (rightChildIndex < heapSize && s[max] < s[rightChildIndex]) {// 注意:此处不能写成s[parentIndex]
			max = rightChildIndex;
		}
		// 如果最大值不是当前结点,那么需要交换。交换后,其子结点可能不是最大堆,需要重新调整,递归
		if (max != parentIndex) {
			int temp = s[parentIndex];
			s[parentIndex] = s[max];
			s[max] = temp;
			maxHeapAdjust(s, heapSize, max);
		}

	}

	public static void heapSort(int[] s) {
		// 最大堆的根结点为最大值,每次与数组最后一位交换,即可获得最大值,该值不再参与堆调整
		// 由于交换操作破坏了最大堆结构,需要再次调整,长度需要减一
		// 由于之前已经是最大堆,目前只有第一个值可能不满足,调整时传入的parentIndex = 0即可
		for (int i = s.length - 1; i > 0; i--) {
			int temp = s[0];
			s[0] = s[i];
			s[i] = temp;
			maxHeapAdjust(s, i, 0);
		}
	}

	private static int getLeftChildIndex(int index) {
		return (index << 1) + 1;
	}

	private static int getRightChildIndex(int index) {
		return (index << 1) + 2;
	}

	private static int getParentIndex(int index) {
		return (index - 1) >> 1;
	}
}
效率分析:
堆排序的平均时间复杂度为O(nlogn),空间复杂度为O(1)。
稳定性:false.

参考文献:


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值