文章目录
1、选择排序
在上一篇中初探比较排序,向大家介绍了插值排序,使得大家对比较排序有个大体的了解,那么在接下来的该篇中将为大家介绍选择排序的思想,当然从字面上可以简单的理解,“选择”必然是要在可选范围内,比较出最优值,就好比生活中我们去瓜棚里挑最大的西瓜一样,首先我们会挑相对较大的西瓜拿在手上,然后再去瓜堆中挑更大的西瓜,直到手上拿着的西瓜是最大的为止;下面我将向大家介绍选择包含的简单选择排序和堆排序;
2、简单选择排序
2.1 原理
从一堆无序元素中,挑出最佳元素,并记住最佳元素的位置,再交换无序元素的首位和最佳位置的元素,通过不断循环以上步骤达到缩小无序范围的目的;
2.2 算法分析
1、 空间复杂度 O(1);
2、 时间复杂度O(N*2)
3、 属于不稳定排序;
2.3 步骤描述
1、 创建临时位置pos指向无序元素的首位;
2、 从左往右遍历无序元素,两两相互比较后,始终让pos指向最优解(最小值位置);
3、 若pos不等于无序元素的首位,那么交换无序首位和pos位置上的元素,否则不动;
4、 循环以上步骤,直到无序范围不断缩小为零为止;
2.4 简单选择排序Java代码
/**
* 选择排序
* 时间复杂度O(N*2)
* @param <T>
* @param a
*/
public static <T extends Comparable<? super T>> void choiseSort(T[] a) {
int pos;
for (int i = 0; i < a.length-1; i++) {
//1、创建临时位置pos指向无序元素的首位;
pos=i;
//2、从左往右遍历无序元素,两两相互比较后,始终让pos指向最优解(最小值位置);
for (int j = i+1; j < a.length; j++) {
if(a[pos].compareTo(a[j])>0) {
pos=j;
}
}
//3、若pos不等于无序元素的首位,那么交换无序首位和pos位置上的元素,否则不动;
if(pos!=i) {
T temp=a[i];
a[i]=a[pos];
a[pos]=temp;
}
}
}
}
3、堆排序
3.1 原理
采用max堆或min堆来存储无序元素,利用堆性质,将堆的根元素与最后一个元素调换,在每次调换后缩小堆的范围,然后维持堆序性质不被破坏,直到最后一个元素执行完以上步骤后结束算法;
3.2 堆性质
- 结构性
堆是一颗被完全填满的二叉树,有可能例外的是在底层,底层上的元素从左到右填入,这样的数成为完全二叉树;
具体实现使用数组表示:
对于数组中任意位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元(2i+1)中,它的父亲则在位置⌊i/2⌋上。
- 堆序性
如果我们考虑任意子树也应该是一个堆,那么任意节点就应该小于(min堆)或者大于(max堆)所有后裔;
Max堆:
3.3 算法分析
1、 时间复杂度:O(N*LogN);
2、 空间复杂度O(1);
3、 属于不稳定排序;
3.4 步骤描述
1、 构造max堆或min堆;
2、 调换树根和最后一个元素,并使得堆的大小heapSize=heapSize-1;
3、 维持堆性质,进行下滤;
4、 重复2、3步骤直到堆大小为1为止;
3.5 堆排序Java代码
/**
* 堆排序
* 时间复杂度O(N*LogN)
* @param <T>
* @param a
*/
public static <T extends Comparable<? super T>> void heapSort(T[] a) {
//1、构建max堆;
for(int i=a.length/2-1;i>=0;i--) {
percDown(a,i,a.length);
}
for(int i=a.length-1;i>0;i--) {
//2、调换树根和最后一个元素;
swap(a,0,i);
//3、维持堆性质,进行下滤;
percDown(a,0,i);
}
}
/**
* 下滤 维持堆序性
* @param <T>
* @param a T数组
* @param i 下滤开始位置
* @param heapSize 堆的大小
*/
private static <T extends Comparable<? super T>> void percDown(T[] a,int i, int heapSize) {
int child;
//存放需要下滤的元素
T temp;
for(temp=a[i];2*i+1<heapSize;i=child) {
//左子节点,因为数组是从0索引开始所以左子节点为2*i+1
child=2*i+1;
//比较左右子子节点的大小
if(child!=heapSize-1 && a[child].compareTo(a[child+1])<0) {
child++;
}
//比较下滤元素与子节点的大小
if(temp.compareTo(a[child])<0) {
a[i]=a[child];
}else {
break;
}
}
//将下滤元素放入到正确位置;
a[i]=temp;
}
/**
* 调换位置
* @param <T>
* @param a T数组
* @param i 位置 i
* @param j 位置 j
*/
private static <T extends Comparable<? super T>> void swap(T[] a, int i,int j) {
T temp=a[i];
a[i]=a[j];
a[j]=temp;
}
4、选择算法测试
package xw.zx.algorithm.sort;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SortTest {
private static final int ARRAY_LEN=100;
private static Integer[] arr=new Integer[ARRAY_LEN];
public static void main(String[] args) {
List<Integer> l=new ArrayList<>();
for (int i = 0; i < ARRAY_LEN; i++) {
l.add(i+1);
}
//乱序列表
Collections.shuffle(l);
//列表转换成数组
arr=l.toArray(new Integer[0]);
System.out.println("输出原数组");
printVal(arr);
//排序
//AllSorts.choiseSort(arr);
AllSorts.heapSort(arr);
System.out.println("输出排序后的数组");
printVal(arr);
}
/**
* 打印数组
* @param arr
*/
private static void printVal(Integer[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println("");
}
}