选择排序

  • 简单选择排序
  • 堆排序

简单选择排序

原理非常简单

n 个元素的数组,i = 1,2,3,…
n-i+1 个元素中选出最大(小)的元素
与第 i个元素交换

当然简单的方法效率不是很理想,很容易看出简单选择排序的时间复杂度为 O(n2)

我的代码如下

public static void sort(int[] data){
        int len = data.length;
        for(int i = 0; i < len; i ++){
            int min = i;
            for(int j = i; j < len; j ++){
                if(data[j] < data[min] ){
                    min = j;
                }
            }
            if(i != min){
                int temp = data[i];
                data[i] = data[min];
                data[min] = temp;
            }
        }
    }

堆排序

首先介绍一下 的概念,

n个元素的序列 , , 当且仅当满足以下关系时,称之为堆

{kik2ikik2i+1()

{kik2ikik2i+1()

其中
(i=1,2,,n2)

这个定义放在一个一维数组上是不好理解的,如果我们把这样的序列看成一颗 完全二叉树 就好理解的多了。

完全二叉树中的所有非叶子结点的值均不大于(不小于)其左、右孩子结点的值。
如图:

堆的完全二叉树表示

由图可知堆顶元素( 树的根结点)是序列的最大(最小)值。
堆排序就是利用了堆的这一特点。
原理如下

n 个元素的数组,i = 1,2,3,…
将数组构造成堆
输出堆顶元素
调整剩余 n - i 个元素构建成堆

问题在于
(1)怎样将无序数组建成堆
(2)怎样调整剩余元素成新堆

调整剩余元素成新堆

大家应该都会觉得第二个问题简单一些,因为剩余元素即左右子树,已经是堆。
堆排序中,当输出堆顶元素后,以最后一个元素代替成为堆顶。仅需自顶而下的比较、调整就能生成新的堆。
如图
这里写图片描述

将无序数组建成堆

如果上一步调整的操作叫做 “筛选”,那么将无序数组建成堆的过程就是重复 “筛选”的过程,我们从第一个非叶子结点(在完全二叉树中 是第 n2 个元素)开始向对所有非叶子结点执行“筛选”。
如图

这里写图片描述

堆排序的时间复杂度

容易看出每次“筛选”的时间复杂度是 O(lgn) 。而完成排序至少执行 n1 次“筛选”。所义堆排序的时间复杂度为 O(nlgn)

我的代码下

/**
     * 堆排序
     * @param data 待排序数组
     */
    public static void sort(int[] data){
        buildMaxHeap(data);
        int temp = 0;
        int size = data.length;
        for(int i = data.length - 1; i > 1; i --){
            temp = data[i];
            data[i] = data[1];
            data[1] = temp;
            size --;
            maxHeapify(data,1,size);
        }
    }

    /**
     * 初次构建堆
     * @param data 待排序数组
     */
    public static void buildMaxHeap(int[] data){
        int len = (data.length-1) / 2;
        int size = data.length;
        for(int i = len; i > 0; i --){
            maxHeapify(data,i,size);
        }
    }

    /**
     * "筛选" 操作
     * @param data 待排序数组
     * @param i    堆顶元素的索引
     * @param size 堆的大小
     */
    public static void maxHeapify(int[] data, int i,int size){
        int l = left(i);
        int r = right(i);
        int largest = 0;
        if(l< size && data[l] > data[i]){
            largest = l;
        }else{
            largest = i;
        }
        if( r < size && data[r] > data[largest]){
            largest = r;
        }
        if(largest != i){
            int temp = data[i];
            data[i] = data[largest];
            data[largest] = temp;
            maxHeapify(data,largest,size);
        }
    }

    /**
     * 得到左孩子
     * @param i 父结点索引
     * @return 左孩子结点索引
     */
    public static int left(int i){
        return i*2;
    }

    /**
     * 得到右孩子
     * @param i 父结点索引
     * @return 右孩子结点索引
     */
    public static int right(int i){
        return i * 2 + 1;
    }

[1] 严蔚敏 . 数据结构(c语言版)
[2] 算法导论

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值