排序算法总结——选择排序(简单选择排序和堆排序)

1.简单选择排序:

       选择排序也是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

       选择排序是不稳定的排序算法,不稳定发生在最小元素与A[i]交换的时刻。

       比如序列:{ 5, 8, 5, 2, 9 },一次选择的最小元素是2,然后把2和第一个5进行交换,从而改变了两个元素5的相对次序。

package cn.liu.made;

/**
 * 两个数字进行交换
 * @author Dick
 *
 */
public class Sort {
	//交换m和n的值,m和n为数组的下标
	public static void sort(int[] arr,int m,int n) {
		int temp = arr[n];
		arr[n]=arr[m];
		arr[m]=temp;
	}
}
package cn.liu.made;

import java.util.Arrays;

/**
 * 选择排序
 * @author Dick
 *
 */
public class SelectionSort {
	public static int[] sleectSort(int[] arr) {
		if(arr==null || arr.length<2) return arr;
		for(int i=0;i<arr.length;i++) {
			//每次将min赋值为需要排序数组的第一位,最后用来存储最小的数
			int min = i;
			//寻找每次最小的数字
			for(int j=i;j<arr.length;j++) {
				if(arr[j]<arr[min]) min = j;	
			}
			//将最小的数字排放到前面相应的位置
			Sort.sort(arr, i, min);
		}
		return arr;
	}
}

2.堆排序 

概念:

        堆:完全二叉树+子节点的树不大于父节点的树

思路解释:

  1. 对一个乱序的二叉树,调用堆化方法heapify()建立成一个堆。
  2. 将此堆的根节点和最后一个叶子结点交换,将叶子节点删去。再将剩下的节点进行堆化进行建成一个堆。

一直重复第第二步,此时这个这个树便从小到大依次排序。

核心:

         heapif():将本次堆化的父节点,左右节点进行比较,然后进行交换,使得这个三个节点组成的小树变为一个堆。然后再去检查进行交换的子节点(此时它为下次的父节点)是否为堆。(heapify()只能将局部的小树建成堆,如果一个乱序的树,从0到尾使用heapify则不会成功建堆,因为在树底可能存在最大的树,但此时已经不能交换到根节点的位置去了。)

 注意:     

         所以,在进行1.建堆时,是从最后一个叶子节点的父节点进行heapify()到根节点0。这样保证了大数全都交换到了上去,而且每个父节点进行heapify()时其他们的子节点如果乱序也会通过递归调用形成堆,最后整体都成为了堆。

        在headSort()中交换值后,为什么不直接调用buildMaxHeap()是,因为此时树只是部分乱序,其他未受影响的子树基本符合堆标准,所以调用heapify()就可以满足,其重新建为堆。

package cn.liu.made;

import java.util.Arrays;

/**
 * 堆排序
 * @author 15349
 *
 */
public class HeapSort {
	//堆排序算法
	public static int[] headSort(int[] tree) {
		//重新拷贝一份数组
		int[] arr = Arrays.copyOf(tree, tree.length);
		//首先对arr进行建堆
		buildMaxHeap(arr);
		//待排序的树的个数
		int len = arr.length;
		//开始最后一个数和第一个数进行交换
		for(int i=len-1;i>0;i--) {
			//第一个数和最后一个数交换
			Sort.sort(arr, i, 0);
			//把最后一个数字,相当于删去
			len--;
			//对进行交换后的树再进行headpify,重新成堆。因为除过交换的部分其他都是堆,所以用heapify就行
			heapify(arr,0,len);
		}
		return arr;
	}
	
	
	//建堆,把一个杂乱的树,建成一个最大堆
	private static void buildMaxHeap(int[] arr) {
		//从最后一个叶子结点的父节点一直向上堆化到根节点
		for(int i=((arr.length-1)/2);i>=0;i--) {
			heapify(arr, i, arr.length);
		}
	}
	
	
	//堆化
	//i是从哪个节点开始Heapify,len是此时树的大小,也就是数组的长度(最大节点下标比len小1)
	private static void heapify(int[] arr,int i,int len) {
		int left = 2*i+1;
		int right = 2*i+2;
		//存根,左,右节点中最大的节点下标
		int max = i;
		if(left<len && arr[max]<arr[left]) {
			max = left;
		}
		if(right<len && arr[max]<arr[right]) {
			max = right;
		} 
		//三个节点现在不是堆,则交换
		if(max!=i) {
			Sort.sort(arr, i, max);
			//检查被交换的子节点以其为父节点的堆是否稳定
			heapify(arr, max, len);
		}
	}
}
发布了159 篇原创文章 · 获赞 86 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_40301026/article/details/94428655