排序2_冒泡、堆排序

1.冒泡(稳定)

视频演示冒泡排序示意图1冒泡排序示意图2
排序思路:在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序。

1.1 程序测试

public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            boolean isSorted = true;
            for (int j = 0; j < array.length - i - 1; j++) {
                // 相等不交换,保证稳定性
                if (array[j] > array[j + 1]) {
                    swap(array, j, j + 1);
                    isSorted = false;
                }
            } 
            if (isSorted) {
                break;
            }
        }
    }

性能分析:
在这里插入图片描述

1.2 比较:插入、选择、冒泡排序

一次使得一个数据有序思想
插入排序在无序区间选择第一个数,在有序区间遍历 查找合适的位置插入
选择排序遍历无序区间 查找最大数/最小数的下标,放到有序区间中
冒泡排序遍历无序区间 通过两两比较,将最大数挤到最后
for(int i = 0;i < array.length-1;i++){
    //插排:j遍历的是有序区间
    //选择、冒泡:j遍历的是无序区间
}

2.堆排序(不稳定)

视频演示堆排序示意图

堆排序:规模大的选择排序(减治排序,没次选择最大的数放后面),利用堆的特性选择最大的数。

排升序要建大堆;排降序要建小堆

从前向后遍历,向上调整;从后向前遍历,向下调整

2.1 建大堆步骤

1)把整个数组建一个大堆。
2)需要选出n-1个数。
i.[0]是无序区间最大的数;
ii.交换[0]和[无序区间最后一个数的位置];
iii.无序区间-1;无序区间堆的特性被破坏;
iiii.针对无序区间做向下调整,重新建一个大堆;
iiiii.重复上述步骤。

2.2 向下调整步骤

1)判断index是不是叶子(不是叶子:2*index+1<size),左孩子下标没越界,调整需继续
2)找到最大孩子下标
i.假设左孩子是最大的
ii.如果有右孩子且右孩子大,大的是右孩子

int max = 2*index+1;
if(2*index+2<size){
    if(array[2*index+2]>array[2*index+1]){
         max = 2*index+2;
    }
}

iii.比较[max]和[index]
如果[index]大,满足堆,调整结束;否则交换,并对[max]继续调整

2.3 程序测试

public class HeapSort {
    public static void heapSort(int[] array) {
        // 1. 建大堆
        createBigHeap(array);

        // 2. 选出 array.length - 1 个数
        for (int i = 0; i < array.length - 1; i++) {
            // 无序 [0, array.length - i)
            // 交换 array[0], array[length - i - 1]
            swap(array, 0, array.length - i - 1); 
            //大堆第一个元素和无序区间最后一个数交换
            // 无序 [0, array.length - i - 1)
            // 无序长度 array.length - i - 1
            shiftDown(array, array.length - i - 1, 0);
            //下标为0的位置开始向下调整
        }
    }

    private static void createBigHeap(int[] array) {
        for (int i = (array.length - 2) / 2; i >= 0; i--) { //(array.length-2)/2为最后一个结点的双亲  保证i的父节点存在
            shiftDown(array, array.length, i);
        }
    }

    private static void shiftDown(int[] array, int size, int i) {
        while (2 * i + 1 < size) { //index非叶子节点,确定i有左孩子
            int max = 2 * i + 1; //假设最大的是左孩子
            /*
            if (max + 1 < size) {
                if (array[max + 1] > array[max]) {
                    max = max + 1; //最大的是右孩子
                }
            }
            */
            if (max + 1 < size && array[max+1] > array[max]) {
                max = max + 1; //大的是右孩子
            }
            if (array[i] >= array[max]) {
                return; //i大 不需要调整
            }

            swap(array, i, max); //否则 需要调整 交换[i] [max]
            i = max; //[max]需要继续向下调整
        }
    }

    private static void swap(int[] array, int i, int j) {
        int t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
    public static void main(String[] args) {
        int[] array = {34,45,12,33,0,1,2,3,88,100};
        heapSort(array);
        System.out.println(Arrays.toString(array));
    }
}

测试结果:
在这里插入图片描述
性能分析:在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值