选择类排序:直接选择与堆排

直接选择排序:整个数组分为有序区和无序区

思想

    一开始整个数组默认是无序区,有序区元素为空,每趟从无序区里面选出一个最小的元素,与无序区的第一个元素进行交换,整个时候有序区的元素的元素+1,无序区的元素会-1,下一趟排序再从无序区选择一个最小的与无序区的元素进行交换,无序区元素-1.有序区+1,以后执行同样的操作

代码如下

void selectSort(int a[],int n){
    for (int i = 0; i<n; i++) {
        int min = a[i];//遍历序列,每次以当前遍历的元素作为最小值
        int small = i;
        //内部循环,寻找无序区中的最小值
        for (int j = i+1; j<n; j++) {
            //如果min比较大,那就把小的那个下标记住
            if (min>a[j]) {
                min  = a[j];
                small = j;//记录每趟选择之后的那个最小值的下标
            }
        }
        //当最小值的下标不是当前元素的时候
        if (small!=i) {
            //将最小值与无序区的第一个元素交换
            int temp = a[small];
            a[small] = a[i];
            a[i] = temp;
        }

    }
}

算法效率

时间复杂度:O(n);
空间复杂度:   O(1);
不稳定排序

直接选择排序的优化之一:对于重复出现的元素,可以记录他的出现次数,最后直接放入数组中就可以
优化之二:堆排:记录之前比较过得记录,防止重复比较

堆排:大顶堆和小顶堆(以下例子对于大顶堆)

思想:

1:构建堆:将数组中的元素构建成一棵完全二叉树
2:初始化堆:对完全二叉树进行调整
* 从最后一个非叶子节点开始,在当前节点以及其左右孩子街节点里面找出一个最大的节点,然后与当前节点交换,其他的也做同样操作,直到根节点位置。
3:排序:每次取出堆的根节点,然后将它与最后一个叶子节点交换,若交换之后破坏了堆的规则,则要重新对堆进行调整,后面进行递归操作
 * 规律就是父节点元素大于或者等于左右孩子节点的元素
 * 调整规则就是在每个堆里面的父节点以及左右孩子节点中找到一个最大的然后与当前堆里面的父节点节点交换,要是调整之后破坏了其他堆的规则,也要对其他堆重新进行调整

2:算法效率:

时间复杂度:由于每次重新恢复堆的时间复杂度为O(logN),共N - 1次重新恢复堆操作,再加上前面建立堆时N / 2次向下调整,每次调整时间复杂度也为O(logN)。二次操作时间相加还是O(N * logN)。故堆排序的时间复杂度为O(N * logN)
空间复杂度:O1)
不稳定排序

3:总结:堆排是每次从前面选择最小或者最大元素,然后将其插入后面的有序区,类似于直接选择排序,采用最小堆得到的是递减的,采用最大堆得到递增序列。

堆排和直接选择排序的比较

直接选择排序中要从 a[0]~a[n-1]个选择一个最小的,需要进行 n-1次比较,要从 a[1]~a[n-1]选择一个最小的又要进行 n-2次比较,但这些比较中的有些可能已经在之前 n-1次比较时候比较过,所以就没有必要,堆排利用树形结构记录了以前的比较记录,所以可以减少重复比较次数,对于大量数据来说优势明显

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值