八大排序Java版 | 全手写 | 可以直接在记事本运行版本

如果要在记事本运行的的话需要将记事本名改为 类名.java,然后javac 类名.java 编译文件,java 类名 运行

冒泡排序

  • 冒泡排序的原理很简单:
    • 遍历数组,每次比较前后两个数字的大小,将较大的数后移。
    • 然后需要进行进行数组长度-1次遍历。
public class Bubble {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        Bubble(nums);
        for (int num : nums) {
            System.out.print(num);
        }
    }

    public static void Bubble(int[] nums){
        for(int i = nums.length - 1;i > 0;i --){//注意,这里i从大到小倒叙
            for(int j = 0;j < i;j ++){
                if(nums[j] > nums[j + 1]){
                    int temp = nums[j];
                    nums[j] = nums[j + 1];
                    nums[j + 1] = temp;
                }
            }
        }
    }
}

选择排序

  • 假定当前索引所代表的数字为最小值,称该索引为最小索引。遍历数组,如果发现有数字比当前数字小,交换该索引和最小索引。完成一次遍历后,最小索引所代表的数字即为最小值,和当前数字交换位置即可。
  • 进行数组长度-1次遍历
public class Choose {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        Choose(nums);
        for(int num:nums){
            System.out.print(num);
        }
    }

    public static void Choose(int[] nums){
        for(int i = 0;i < nums.length - 1;i ++){
            int minIndex = i;
            for(int j =i+1;j < nums.length;j ++){
                if(nums[j] < nums[minIndex]){
                    minIndex = j;
                }
            }
            int temp = nums[minIndex];
            nums[minIndex] = nums[i];
            nums[i] = temp;
        }
    }
}

插入排序

  • 将待排序数组分为两部分:已排序数组和未排序数组。
  • 取未排序数组的第一个数,倒叙遍历已排序数组,依次和已排序数组中的数比较,若该数小于已排序数组中的数,则交换位置。
public class Insert {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        Insert(nums);
        for (int num : nums) {
            System.out.print(num);
        }
    }

    public static void Insert(int[] nums){
        for(int i = 0;i < nums.length - 1;i ++){
            for(int j = i;j >= 0;j --){
                if(nums[j + 1] < nums[j]){
                    int temp = nums[j + 1];
                    nums[j + 1] = nums[j];
                    nums[j] = temp;
                }
            }
        }
    }
}

希尔排序

  • 定义增量长h使得数组分成多个组,每组两个数字进行比较交换
    • 缩小增量长,当h<1时结束排序
  • 在希尔排序中,增长量h并没有固定的规则;我这里假定了一种h的限制方法
public class Shell {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        Shell(nums);
        for (int num : nums) {
            System.out.print(num);
        }
    }

    public static void Shell(int nums[]){
        int N = nums.length;
        //一种h的定义方法
        int h = 1;
        while(h < N / 2){
            h =  h * 2 + 1;
        }

        while(h >= 1){
            for(int i = h;i < N;i ++){
                for(int j = i;j >= h;j -= h){
                    if(nums[j-h] > nums[j]){
                        int temp = nums[j-h];
                        nums[j-h] = nums[j];
                        nums[j] = temp;
                    }else{
                        break;
                    }
                }
            }
            h = h/2;
        }
    }
}

归并排序

  • 先分(sort),再合(Merge)
    • 分治法
    • 利用了递归(所以不能忘了退出条件)
    • 利用了一个辅助数组,在merge中用到的,最后也要将辅助数组的内容还给原数组

public class Merge {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        sort(nums);
        for (int num : nums) {
            System.out.print(num);
        }
    }
    static int[] assist;
    public static void sort(int[] nums){
        assist =  new int[nums.length];
        int lo = 0;
        int hi =  nums.length - 1;
        sort(nums,lo,hi);
    }

    public static void sort(int[] nums, int lo, int hi) {
        if(hi <= lo){
            return;
        }
        int mid = lo + (hi-lo)/2;
        sort(nums,lo,mid);//分1
        sort(nums,mid+1,hi);//分2
        merge(nums,lo,mid,hi);//治
    }

    public static void merge(int[] nums,int lo,int mid,int hi){
    int i = lo;//指向辅助数组的头
    int p1 = lo;//指向(被分开的)前一个数组的头
    int p2 = mid + 1;//指向(被分开的)后一个数组的头

    while(p1 <= mid && p2 <= hi){//根据两个数组中数的大小,放到辅助数组中
        if(nums[p1] < nums[p2]){
            assist[i++] = nums[p1++];
        }else{
            assist[i++] = nums[p2++];
        }
    }

    while(p1 <= mid){//清空(被分开的)前一个数组,全部放到辅助数组
        assist[i++] = nums[p1++];
    }
    while(p2 <= hi){清空(被分开的)后一个数组,全部放到辅助数组
        assist[i++] = nums[p2++];
    }

        for(int index = lo;index <= hi;index ++){//辅助数组的内容还给原数组
            nums[index] =  assist[index];
        }
    }
}

快速排序

  • 快速排序的原理和归并排序类似,不过归并排序是从中间切分,并且切分后需要再合起来。而快速排序需要设计一个算法找到一个切分值,我们对切分好的每一段进行排序
  • 找到切分值的算法:假定我们的第一个元素就是切分值,我们通过调整使得他称为真正的切分值:定义一个指向头以及一个指向尾部往后一位的指针,一个往后扫描,当扫描到某个数(下标left)大于假定的切分值时停止;一个往前扫描,当扫描到某个数(下标right)小于假定的切分值时停止。
    • 如果left >= right就直接退出了。这个时候一般left == right,他们的值已经达到了切分值的要求,我们将这个值和第一个元素交换,就达成了目标。
    • 否则应该交换两个数的位置,使得左边的都小于切分值,右边的都大于切分值。利用一个while循环继续这个操作。
public class Quick {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        sort(nums);
        for (int num : nums) {
            System.out.print(num);
        }
    }

    public static void sort(int[] nums){
        int lo = 0;
        int hi = nums.length - 1;
        sort(nums,lo,hi);
    }

    public static void sort(int[] nums,int lo,int hi){
        if(lo >= hi){ 
            return;
        }
        int p1 = part(nums,lo,hi);//找出切分值
        sort(nums,lo,p1-1);
        sort(nums,p1+1,hi);
    }

    public static int part(int[] nums, int lo, int hi){
        int key = nums[lo];
        int left = lo;
        int right = hi + 1;
        while(true){
            while(key < nums[--right]){
                if(right == lo){
                    break;
                }
            }
            while(key > nums[++left]){
                if(left == hi){
                    break;
                }
            }

            if(left >= right){
                break;
            }else{
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
            }
        }
        int ktemp = nums[lo];
        nums[lo] = nums[right];
        nums[right] = ktemp;

        return right;
    }
}

堆排序

  • 堆排序需要首先构造堆,然后再进行排序。我们这里利用的是大顶堆,所谓大顶堆也就是从顶向下,数字是从大到小的。所以我们每次交换大顶堆的第一个和未排序的最后一个,(每次交换完后需要进行一次下沉以保证其大顶堆的特性),这样交换完成后就可以实现从小到大的排序。
  • 如何构造大顶堆?从二分之一处往前扫描,不停的下沉。
  • 当然也不能忘记将堆的内容还给数组。
public class HeapSort {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        sort(nums);
        for(int num:nums){
            System.out.print(num);
        }
    }

    public static void sort(int[] nums){
        //1.建立堆heap|堆的0号位置是空出来的,所以用一个新的数组进行复刻
        int[] heap = new int[nums.length + 1];
        System.arraycopy(nums,0,heap,1,nums.length);
        for(int i = (heap.length - 1) / 2;i > 0;i --){//这里是>0不是>=0!!!!!!!!!!
            sink(heap,i,heap.length-1);//-1是因为堆长度多出来一位
        }


        //2.排序|交换堆顶元素和最后一个元素并下沉
        for(int i = heap.length - 1;i > 1;i--){
            int temp = heap[i];
            heap[i] = heap[1];
            heap[1] = temp;
            sink(heap,1,i-1);//这里i-1也很容易错
        }


        //3.收尾工作,把堆还给nums
        System.arraycopy(heap,1,nums,0,nums.length);
    }


    //下沉
    //找到子节点中较大的值的下标,如果target < 较大的值,就需要交换
    //大大的问题,堆的大小直接显示在序号上了//这里max代表的是下标
    public static void sink(int[] heap,int target,int range){
        while(2 * target <= range){//至少左子节点
            int max = 2 * target;//这里max代表的是下标
            if(2 * target + 1 <= range){//如果存在右子节点
                if(heap[2 * target + 1] > heap[2 * target]){
                    max = 2 * target + 1;
                }
            }

            if(heap[target] < heap[max]){//如果target < 较大的值,就需要交换
                int temp = heap[target];
                heap[target] = heap[max];
                heap[max] = temp;
            }

            //更新target的值,进行下一个
            target = max;
        }
    }
}

基数排序(也叫桶排序)

  • 基础排序需要对每一位(个、十、百、千、万)进行排序,每一位的排序都需要放进桶,再拿回数组,这样就使得每一位都有顺序
    • 首先 ,确定他的最高位是多少,找出最大数,最大数的位数就是最高位
    • 造桶,造一个计数器
    • 循环操作(放进桶,拿回数组)
package com.zhang.eightsort;
public class BaseSort {
    public static void main(String[] args) {
        int[] nums = {341,92,1,7,432,66,78,9};
        sort(nums);
        for (int num : nums) {
            System.out.print(num+" ");
        }
    }
    
    public static void sort(int[] nums){
        //1.找出最大位是哪一位|    先找最大的数,然后看他的位数
        int maxNum = nums[0];
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] > maxNum){
                maxNum = nums[i];
            }
        }//331
        int maxLen = Integer.toString(maxNum).length();//3
        
        
        //2.开始造桶  10 x nums.length
        //并且把数据都放进桶里
        int[][] bucket = new int[10][nums.length];
        int[] counts = new int[10];//创建10个计数器
        int div = 1;
        for(int i = 0;i < maxLen;i ++){//每次都要放进桶再拿出来
            for(int j = 0 ;j < nums.length;j ++){
                int temp = nums[j] / div % 10;//比如说余3
                bucket[temp][counts[temp]++] = nums[j];
            }
            div *= 10;
        int total = 0;
        //从桶里把数据放回数组
        for(int n = 0;n < 10;n++){//10 个桶
            for(int j = 0;j < counts[n];j ++){
                nums[total++] = bucket[n][j];//total别忘了++
            }
            counts[n] = 0;//这个清空桶的操作还挺关键,不然会数组下标越界
        }
    }//这个括号放在这也有讲究,每排一次都要放回一次数组中。
    }
}

猜你喜欢

转载自blog.csdn.net/dolpin_ink/article/details/123488937