八大基础排序算法


稳定排序
前提:只有当在"二次"排序时不想破坏原先的次序,稳定性才有意义

概念:数据排序前后依然能保持相同数据的相对顺序
例子:对数组[3,3,1]进行选择排序算法进行排序,拿出最大的数3和最小的数1交换位置后变为[1,3,3],此时第一个3的下标本来是0,现在变成了2,排在了第二个3的后面.没有保持原先第一个3依旧保持在第二个3的前面的的相对顺序,这就是不稳定的排序

意义:如果我们只对一串数字排序,那么稳定与否确实不重要,因为一串数字的属性是单一的,就是数字值的大小.但是排序元素往往不只一个属性,像我们对一群人进行年龄排序,但是人除了年龄还有身高体重属性,在年龄相同时如果不想破坏原先身高体重的次序,就必须使用稳定的排序算法
例子:
像这样一组人的数据[[age:15,height:15,weight:45],[age:5,height:25,weight:55],[age:5,height:35,weight:65]]我们需要排序后保持 体重身高的由大到小顺序像这样[[age:5,height:25,weight:55],[age:5,height:35,weight:65],[age:15,height:15,weight:45]],如果我们使用选择排序这样的不稳定算法,排序一次得到的结果是[[age:5,height:35,weight:65],[age:5,height:25,weight:55],[age:15,height:15,weight:45]]这样人的体重身高的顺序就被破坏了

冒泡排序

	时间复杂度:O(n²)
	空间复杂度:O(1)
	简单描述:数组中的数据两两之间相比,大的数排到最后面,像冒泡一样
	具体实现逻辑:
	(1)外层循环for控制循环次数
	(2)内层循环for控制比较次数
	(3)每次循环之后,找到这次比较中最大的数,比较次数减一
	优化思路:如果一趟排序之后没有发生位置交换变化,那么此时就是有序的

详细实现演示:

		//创建一个数组
        int[] nums = {11,78,3,5,6,7};
        //交换数据的中间变量
        int temp;
		//算法描述
        //1.    i从0开始,i与i+1进行比较,如果i>i+1就进行交换
        //2.    i不断增加,直到i<n-1(n是数组元素的个数,n-1是数组元素的最后一个元素),一趟下来,
        //      可以让数组元素中最大值排在数组的最后面
        //第一趟排序
        //第一位和第二位比较
        if (nums[0] > nums[1]){
            //交换
            temp = nums[0];
            nums[0] = nums[1] ;
            nums[1] = temp;
        }

        //第二位与第三位比较
        if (nums[1] > nums[2]){
            temp = nums[1];
            nums[1] = nums[2];
            nums[2] = temp;
        }
        //第三位和第四位比较
        if (nums[2] > nums[3]){
            temp = nums[2];
            nums[2] = nums[3];
            nums[3] = temp;
        }
        //第四位和第五位比较
        if (nums[3] > nums[4]){
            temp = nums[3];
            nums [3]= nums[4];
            nums[4] = temp;
        }
        //第五位和第六位比较
        if (nums[4] > nums[5]){
            temp = nums[4];
            nums[4] = nums[5];
            nums[5] = temp;
        }
        System.out.println(Arrays.toString(nums));

        //第二趟排序(此时最后一位已经是数组最大的数了,不用再参与比较,这次我们找的是第二大的数)
        //第一位和第二位比较
        if (nums[0] > nums[1]){
            //交换
            temp = nums[0];
            nums[0] = nums[1] ;
            nums[1] = temp;
        }

        //第二位与第三位比较
        if (nums[1] > nums[2]){
            temp = nums[1];
            nums[1] = nums[2];
            nums[2] = temp;
        }
        //第三位和第四位比较
        if (nums[2] > nums[3]){
            temp = nums[2];
            nums[2] = nums[3];
            nums[3] = temp;
        }
        //第四位和第五位比较
        if (nums[3] > nums[4]){
            temp = nums[3];
            nums [3]= nums[4];
            nums[4] = temp;
        }
        System.out.println(Arrays.toString(nums));

简化代码:

		//创建一个数组
        int[] nums = {11,78,3,5,6,7};
        //交换数据的中间变量
        int temp;
        //代码简化
        //用双重循环
        //外循环:     控制循环的次数  (4个数据排序,只需要循环3次,因为每次		循环都会找到最大的数,3次循环找到了三个数据,最后一个自然就是最小的)
        //内循环:     控制每趟循环比较的次数
        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j+1]){
                    temp = nums[j];
                    nums[j] = nums[j+1];
                   nums[j+1] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(nums));

优化代码:

		//从上面的例子可以看出,在数据足够乱的情况下需要进行五趟比较才能将数据完整排好序
        //但是实际上第二趟之后数据已经是排好序的,我们的程序在第二躺之后还是会进行第三\四\五趟
        //这里我们进行优化:
        //当一趟排序中并没有出现交换位置.此时数据就是排好序的,直接退出来
        //创建一个数组
        int[] nums = {11,78,3,5,6,7};
        //交换数据的中间变量
        int temp;
        int count = 0;
        //如果发生了位置交换,记录下来
        boolean isChange;
        //外层循环是排序趟数
        for (int i = 0; i < nums.length - 1; i++) {
            //每趟排序重新初始化
            isChange = false;

            //内层循环是当前趟数需要比较的次数
            for (int j = 0; j < nums.length - i - 1; j++) {
                if (nums[j] > nums[j+1]){
                    temp = nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = temp;
                    isChange = true;
                }
            }

            //每一趟进行判断是否发生了位置交换
            if (!isChange){
                break;
            }
            //记录循环的趟数
            count++;
        }
        System.out.println(Arrays.toString(nums));
        System.out.println("循环的趟数为"+count);

选择排序

	时间复杂度:O(n²)
	空间复杂度:O(1)
	简单描述:每次选出最大(或者最小)的数插入到末尾(或者起始)
	具体实现:
	(1)外层循环for控制次数
	(2)内层循环for找出最大值的下标
	(3)找到最大值下标后,进行交换
	优化代码:同时获取最大值和最小值,然后分别插入尾部和首部

代码演示:

		int[] nums = {2,2,1,5,3,4};
        //第一趟排序
        //假定max是最大的
        int max = 0;

        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > max) {
                max = nums[i];
            }
        }
        //使用中间变量进行变量交换
        int temp;
        temp = nums[5];
        nums[5] = nums[3];
        nums[3] = temp;
        System.out.println(Arrays.toString(nums));

        //第二趟排序(再次从数组中获取最大的数,除了已经排好的那个)
        int max2 = 0;
        for (int i = 0; i < nums.length - 1; i++) {
            if (nums[i] > max2){
                max2 = nums[i];
            }
        }
        //再将获取到的最大值与数组倒数第二位交换
        temp = nums[4];
        nums[4] =  nums[3];
        nums[3] = temp;
        System.out.println(Arrays.toString(nums));

代码简化:

		//代码简化
        int[] nums = {2,2,1,5,3,4};
        //记录当前趟数的最大值下标
        int index = 0;
        //变量交换的第三方变量
        int temp;

        //外层循环控制需要排序的趟数
        for (int i = 0; i < nums.length - 1; i++){
            //每趟开始前把最大下标初始化
            index = 0;

            //内层循环控制遍历数组个数,并得到对大值下标
            for (int j = 0; j < nums.length - i; j++){
                if (nums[j] > nums[index]){
                    index = j;
                }
            }
            //内循环结束,找到最大值
            temp = nums[index];
            nums[index] = nums[nums.length - i -1];
            nums[nums.length - i - 1] = temp;
        }
        System.out.println(Arrays.toString(nums));

代码优化:

		//优化
        int[] nums = {2,2,1,5,3,4};
        //最大值下标
        int max = 0;
        //最小值下标
        int min = 0;
        //变量交换的第三方变量
        int temp;
        int count = 0;
        //外层循环
        for (int i = 0; i < nums.length - 1; i++) {
            count ++;
            //初始化最大值最小值的下标
            max = i;
            min = i;

            //内层循环
            for (int j = i; j < nums.length - i; j++) {
                if (nums[j] > nums[max]){
                    max = j;
                }
                if (nums[j] < nums[min]){
                    min = j;
                }
            }
            //每次取完值判断两个下标的情况
            // 1.最大值最小值下标重合,排序完成
            // 2.最小值下标超出最大值下标
            if (max == min || max < min){
                break;
            }
            System.out.println(nums[max]);
            //每趟循环完成,插入最大值最小值
            temp = nums[max];
            nums[max] = nums[nums.length - i- 1];
            nums[nums.length - i - 1] = temp;

            System.out.println(nums[min]);
            temp = nums[min];
            nums[min] = nums[i];
            nums[i] = temp;
        }
        System.out.println("===========================");
        System.out.println(count);
        System.out.println(Arrays.toString(nums));

插入排序

快速排序

归并排序

希尔排序

堆排序

桶排序(基数排序)

(未完待续)
稳定算法:冒泡排序、插入排序、归并排序、基数排序
不稳定算法 :选择排序、快速排序、希尔排序、堆排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值