重要的排序算法总结【java实现】

引入

几种排序算法的比较

在这里插入图片描述


桶排序

桶排序思路

对于一个待排序的数组,可以将数组中的数据分配到有限的“桶”中。这个桶可以再次申请一个数组来实现。同时,需要对又申请的数组中的元素初始化为0。在进行排序时,会将原数组中的值作为“桶数组”的下标,每遇到一个原数组中的值,就将桶数组中的对应下标值加一。最后遍历一遍“桶数组”,值为0的跳过,不为0的代表某个值出现的次数。
代码:

public class BucketSocket {
    public static void main(String[] args) {
        int[] nums = {4,3,5,5,3,8,199,3433,199,8,5,1,6,77};
        nums = bucketSort(nums);
        for(int a:nums){
            System.out.print(a+"  ");
        }
        System.out.println();
    }
    //桶排序
    //缺陷:桶排序适用于数组中的数字比较小,数值比较集中的情况,当数组中的数值域分布不均匀时,需要申请很大的数组空间。
    //     桶排序不适用于数组中有负数的情况,因为数组不能作为数组的下标
    public static int[] bucketSort(int[] nums){
        int len = nums.length;
        int[] flag = new int[50000];
        for(int i =0;i<flag.length;i++){
            flag[i] = 0;
        }

        for(int i =0;i<len;i++){
            flag[nums[i]]++;
        }
        int t = 0;
        for(int i =0;i<50000;i++){
            while (flag[i]!=0){
                nums[t++] = i;
                flag[i]--;
            }
        }
        return nums;
    }
}


快速排序

快排原理

快速排序是对冒泡排序的一种改进,二者的相同点是:均需要进行很多次的比较和移动指针来确定排序序列。快速排序的优点是增加了比较和移动的距离,将关键字较大的元素直接从前面放到后面,将关键字较小的元素直接从后面放到前面,减少了比较和交换的次数。

基本过程

1.从数组的第一个元素值作为分界点开始,用key来保存,使用两个指针high指针和low指针,high指针从后往前遍历,找到第一个小于key的元素值,并用该值替换nums[low];一个从前往后遍历,找到第一个大于key的元素值,并用该值替换nums[high]。
2.将key值赋值给当前的nums[low]。并返回low的下标作为第一次分割的位置。
3.递归对前半部分和后半部分的值进行相同的操作,知道整个数组有序为止。

代码:

public class QuickSort1 {
    public static void main(String[] args) {
        QuickSort1 q = new QuickSort1();
        int[] nums = {-2,-1,1,3,-7,-6,-8};
        q.quick(nums,0,nums.length-1);
        for(int a:nums){
            System.out.print(a+" ");
        }
        System.out.println();
    }
    public  void quick(int[] nums,int low,int high){
        int len = nums.length;
        if(low<high) {
            int pos = getPos(nums, low, high);
            quick(nums, low, pos - 1);
            quick(nums, pos + 1, high);
        }
    }
    private int getPos(int[] nums,int low,int high){
        int key = nums[low];
        while(low<high){
            while (low<high && nums[high]>=key)
                high--;
            nums[low] = nums[high];
            while (low<high &&nums[low]<=key)
                low++;
            nums[high] = nums[low];
        }
        nums[low] = key;
        return low;
    }
}

快速排序的稳定性

快速排序是一种不稳定的算法,为什么这么说呢?
我们知道,我们在进行每一趟快排时,都会将某一个元素作为待比较元素,分为从两头开始比较,并将大于等于该元素的值和小于等于该元素的值以该元素分为两部分。当遇到以下待排列数组时,就不能保证每一趟快排是稳定的。举个栗子:
待排数组:6,9,9,10,11

我们选择第一个9作为主元(过程是随机的),若把小于等于放在主元的左边,则第二个9就跑到第一个9左面了,从而导致不稳定
主元的选择是随机的,导致不稳定的原因在于我们无法保证每次都是稳定的,所以它是不稳定的。

堆排序

堆排序原理

首先,堆排序利用了大顶堆/小顶堆的性质,使用完全二叉树的数据结构在数组中对一串数字完成排序。

堆排序过程

1.首先要将待排序数组构造成一个大顶堆或者小顶堆。
2.调换数组的首元素和尾元素,数组的size-1.
3.将剩下size数目的数据再次构造为大顶堆/小顶堆。
4.重复2,3步骤,直到数组的size为0.
注意:
若在排序时将数组构造为大顶堆,排序后的数组为升序排列。
若在排序时将数组构造为小顶堆,排序后的数组维降序排列。
代码:

/**
 * 堆排序的主要思路:
 *  1.将待排序元素构造成一个大顶堆(或者小顶堆)。
 *  2.将第一个根节点与数组的最后一个元素交换,此时,最后一个元素为最大值。
 *  3.将剩下的n-1和元素也构造成同样的堆,并继续交换找出最大值。
 *  4.按照这个过程依次进行。
 *  5.得到排序序列。
 *
 */
public class HeapSort {
    public static void main(String[] args) {
        //int a[] = new int[8];
        int[] a = {4,3,6,77,-1,24,7};
        for(int i =0;i<a.length;i++){
            System.out.print(a[i]+" ");
        }
        System.out.println();
        System.out.println("============================");
        heapSort(a);
        for(int i =0;i<a.length;i++){
            System.out.print(a[i]+" ");
        }
    }
    //堆排序
    public static void heapSort(int[] arr) {
        //构造大根堆
        heapInsert(arr);
        int size = arr.length;
        while(size>1){
            //固定最大值
            swap(arr,0,size-1);
            size--;
            heapify(arr,0,size);
        }
    }
    //构造大根堆(通过新插入的数上升)
    public static void heapInsert(int[] arr){
        for(int i = 0;i<arr.length;i++){
            //从当前插入的索引
            int currentIndex = i;
            int fatherIndex = (currentIndex - 1)/2;
            //如果当前插入的值大于其父节点的值,则交换值,并且将索引指向父节点
            //然后继续和上面的父节点值比较,直到不大于父节点,则退出循环
            System.out.println(fatherIndex);
            while(arr[currentIndex] > arr[fatherIndex]){
                //交换当前节点与父节点
                swap(arr,currentIndex,fatherIndex);
                //将当前索引指向父索引
                currentIndex = fatherIndex;
                //重新计算当前索引的父索引
                fatherIndex =  (currentIndex - 1)/2;
            }
        }
    }
    //将剩余的数构造成大根堆
    public static void heapify(int[] arr,int index,int size){
        int left = 2*index + 1;
        int right = 2*index + 2;
        while(left<size){
            int largestIndex;
            //判断孩子中较大的值的索引(要确保右孩子在size范围之内)
            if(arr[left] < arr[right] && right<size){
                largestIndex = right;
            }else{
                largestIndex = left;
            }
            //比较父节点的值与孩子中较大的值,并确定最大值的索引
            if(arr[index] > arr[largestIndex]){
                largestIndex = index;
            }
            //如果父节点索引是最大值的索引,那已经是大根堆了,则退出循环
            if(index == largestIndex){
                break;
            }
            //父节点不是最大值,与孩子中较大的值交换
            swap(arr,largestIndex,index);
            //将索引指向孩子中较大值的索引
            index = largestIndex;
            //重新计算交换之后的孩子的索引
            right = 2*index+2;
            left = 2*index+1;
        }
    }
    //交换数组中两个元素的值
    public static void swap(int[] arr,int i ,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值