博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
选择排序算法---直接选择排序和堆排序
阅读量:4950 次
发布时间:2019-06-11

本文共 5336 字,大约阅读时间需要 17 分钟。

本文主要是解析选择排序算法:直接选择排序和堆排序。

 

一、直接选择排序                                                                                                

 

 

基本思想:       

      选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。

 
算法实现:
 
public static void selectSort(int[] data) {        System.out.println("开始排序");        int arrayLength = data.length;        // 依次进行n-1趟比较, 第i趟比较将第i大的值选出放在i位置上。        for (int i = 0; i < arrayLength - 1; i++) {            // 第i个数据只需和它后面的数据比较            for (int j = i + 1; j < arrayLength; j++) {                // 如果第i位置的数据 > j位置的数据, 交换它们                if (data[i] > data[j]) {                    int tmp = data[i];                    data[i] = data[j];                    data[j] = tmp;                }            }            System.out.println(java.util.Arrays.toString(data));        }    }    public static void main(String[] args) {        int[] array = new int[10];        for (int k = 0; k < array.length; k++) {            array[k] = (int) (Math.random() * 100);        }        System.out.print("排序之前结果为:");        System.out.println(java.util.Arrays.toString(array));        System.out.println("");        selectSort(array);    }

 

排序结果:

排序之前结果为:[37, 93, 97, 9, 66, 68, 19, 5, 67, 45]开始排序[5, 93, 97, 37, 66, 68, 19, 9, 67, 45][5, 9, 97, 93, 66, 68, 37, 19, 67, 45][5, 9, 19, 97, 93, 68, 66, 37, 67, 45][5, 9, 19, 37, 97, 93, 68, 66, 67, 45][5, 9, 19, 37, 45, 97, 93, 68, 67, 66][5, 9, 19, 37, 45, 66, 97, 93, 68, 67][5, 9, 19, 37, 45, 66, 67, 97, 93, 68][5, 9, 19, 37, 45, 66, 67, 68, 97, 93][5, 9, 19, 37, 45, 66, 67, 68, 93, 97]

 

算法分析

(1)关键字比较次数

     无论文件初始状态如何,比较次数与关键字的初始状态无关,在第i趟排序中选出最小关键字的记录,需做n-i次比较,因此,总的比较次数为:
     N=(n-1)+(n-2)+...+1=n\times(n-1)/2 =0(n2)
(2)记录的移动次数
     当初始文件为正序时,移动次数为0
     文件初态为反序时,每趟排序均要执行交换操作,总的移动次数取最大值3(n-1)。

       交换次数O(n),最好情况是,已经有序,交换0次;最坏情况是,逆序,交换n-1次。交换次数比冒泡排序较少,由于交换所需CPU时间比比较所需的CPU时间多,n值较小时,选择排序比冒泡排序快

     直接选择排序的平均时间复杂度为O(n2)。
(3)直接选择排序是一个就地排序
(4)稳定性分析
     直接选择排序是不稳定的,原地操作几乎是选择排序的唯一优点

 

 

二、堆排序                                                                                                

 

首先,关于堆的概念这里就不说了,详情请看《算法导论》

堆排序的关键在于建堆,下面简单介绍一下建堆的过程:

第1趟将索引0至n-1处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的最后一个节点交换,就使的这组数据中最大(最小)值排在了最后。

第2趟将索引0至n-2处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的倒数第二个节点交换,就使的这组数据中最大(最小)值排在了倒数第二位。

......

第k趟将索引0至n-k处的全部数据建大顶(或小顶)堆,就可以选出这组数据的最大值(或最小值)。将该堆的根节点与这组数据的倒数第k个节点交换,就使的这组数据中最大(最小)值排在了倒数第k位。

所以我们只是在重复做两件事:

  • 1:建堆
  • 2:拿堆的根节点和最后一个节点交换

 

下面通过一组数据说明:

9,79,46,30,58,49

1:先将其转换为完全二叉树,如图

2:完全二叉树的最后一个非叶子节点,也就是最后一个节点的父节点。最后一个节点的索引为数组长度len-1,那么最后一个非叶子节点的索引应该是为(len-1)/2.也就是从索引为2的节点开始,如果其子节点的值大于其本身的值。则把他和较大子节点进行交换,即将索引2处节点和索引5处元素交换。交换后的结果如图:

建堆从最后一个非叶子节点开始即可

3:向前处理前一个节点,也就是处理索引为1的节点,此时79>30,79>58,因此无需交换。

4:向前处理前一个节点,也就是处理索引为0的节点,此时9<79,9<49,因此无需交换。应该拿索引为0的节点与索引为1的节点交换,因为79>49.如图

5:如果某个节点和它的某个子节点交换后,该子节点又有子节点,系统还需要再次对该子节点进行判断。如上图因为1处,3处,4处中,1处的值大于3,4出的值,所以还要交换。

 

        

算法实现:

public class HeapSort {    public static void heapSort(int[] data) {        System.out.println("开始排序");        int arrayLength = data.length;        // 循环建堆        for (int i = 0; i < arrayLength - 1; i++) {            // 建堆            builMaxdHeap(data, arrayLength - 1 - i);            // 交换堆顶和最后一个元素            swap(data, 0, arrayLength - 1 - i);            System.out.println(java.util.Arrays.toString(data));        }    }    // 对data数组从0到lastIndex建大顶堆    private static void builMaxdHeap(int[] data, int lastIndex) {        // 从lastIndex处节点(最后一个节点)的父节点开始        for (int i = (lastIndex - 1) / 2; i >= 0; i--) {            // k保存当前正在判断的节点            int k = i;            // 如果当前k节点的子节点存在            while (k * 2 + 1 <= lastIndex) {                // k节点的左子节点的索引                int biggerIndex = 2 * k + 1;                // 如果biggerIndex小于lastIndex,即biggerIndex + 1                // 代表的k节点的右子节点存在                if (biggerIndex < lastIndex) {                    // 如果右子节点的值较大                    if (data[biggerIndex] < data[biggerIndex + 1]) {                        // biggerIndex总是记录较大子节点的索引                        biggerIndex++;                    }                }                // 如果k节点的值小于其较大子节点的值                if (data[k] < data[biggerIndex]) {                    // 交换它们                    swap(data, k, biggerIndex);                    // 将biggerIndex赋给k,开始while循环的下一次循环,                    // 重新保证k节点的值大于其左、右子节点的值。                    k = biggerIndex;                } else {                    break;                }            }        }    }    // 交换data数组中i、j两个索引处的元素    private static void swap(int[] data, int i, int j) {        int tmp = data[i];        data[i] = data[j];        data[j] = tmp;    }        public static void main(String[] args) {        int[] array = new int[10];        for (int k = 0; k < array.length; k++) {            array[k] = (int) (Math.random() * 100);        }        System.out.print("排序之前结果为:");        System.out.println(java.util.Arrays.toString(array));        System.out.println("");        heapSort(array);    }}

 

排序结果:

排序之前结果为:[18, 14, 33, 42, 2, 63, 62, 97, 94, 63]开始排序[2, 94, 63, 42, 63, 33, 62, 18, 14, 97][14, 63, 63, 42, 2, 33, 62, 18, 94, 97][14, 42, 63, 18, 2, 33, 62, 63, 94, 97][14, 42, 62, 18, 2, 33, 63, 63, 94, 97][14, 42, 33, 18, 2, 62, 63, 63, 94, 97][2, 18, 33, 14, 42, 62, 63, 63, 94, 97][14, 18, 2, 33, 42, 62, 63, 63, 94, 97][2, 14, 18, 33, 42, 62, 63, 63, 94, 97][2, 14, 18, 33, 42, 62, 63, 63, 94, 97]

 

 

 

转载于:https://www.cnblogs.com/ITtangtang/p/3961898.html

你可能感兴趣的文章
【设计模式系列】--抽象工厂
查看>>
JqueryValidate 动态添加验证
查看>>
双活数据中心的架构
查看>>
大数据公司Palantir融得7亿美元 曾追踪拉登
查看>>
先行者长虹佳华超融合市场沙龙在京举行
查看>>
建立备份策略的重要性
查看>>
小白用户如何轻松上云 -我的轻量应用服务器探索记
查看>>
BCG与阿里研究院等联合揭秘中国互联网经济:成功的关键是什么?
查看>>
发力IoT领域 Marvell注重生态系统发展
查看>>
数据中心网络布线工程必备七大件
查看>>
20个问题揭穿冒牌数据科学家
查看>>
你应该知道的 RPC 原理
查看>>
Ubuntu安装词典
查看>>
KVM虚拟机在线添加网卡
查看>>
Spring解析
查看>>
支付宝签约教程及注意事项
查看>>
设计模式——组合模式(Composite Pattern)
查看>>
java设计模式之——代理模式
查看>>
Perl DBI模块的例子
查看>>
python中str和repr区别
查看>>