排序的基础算法

冒泡排序:

相邻的元素进行比较。
public class 冒泡排序 {
    public static void main(String[] args) {
        int[] a = {2, 8, 20, 6, 7, 8, 5, 8, 100, 9};
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a.length-i-1; j++) {
                if (a[j]>a[j+1]) {
                    exch(a, j, j+1);
                }
            }
        }
        System.out.println(Arrays.toString(a));
    }

    //交换
    private static void exch(int[] a, int i, int j) {
        int temp = a[j];
        a[j] = a[i];
        a[i] = temp;
    }

    //比较
    private static boolean less(int i, int j) {
        return i > j;
    }
}

选择排序:

每轮首位与最小(或最大)索引所对应的元素进行比较

public class 选择排序 {
    public static void main(String[] args) {
        int[] a = {2, 8, 20, 6, 7, 8, 5, 8, 100, 9};
        int temp;
        System.out.println(Arrays.toString(a));
        for (int i = 0; i < a.length; i++) {
            int min = i;
            for (int j = i + 1; j < a.length; j++) {
                if (a[min] > a[j]) min = j;
            }
            exch(a, i, min);
        }
        System.out.println(Arrays.toString(a));
    }

    private static void exch(int[] a, int i, int j) {
        int temp = a[j];
        a[j] = a[i];
        a[i] = temp;
    }
}

插入排序:

相邻元素进行比较,每一轮比较结束,数组都是有序的
public class 插入排序 {
//使用交换
    public static void main(String[] args) {
        int[] a = {2, 8, 20, 6, 7, 5, 100, 9};
        for (int i = 1; i < a.length; i++) {
            for (int j = i; j > 0 && less(a[j], a[j-1]); j--) {
                exch(a, j);
            }
        }
        System.out.println(Arrays.toString(a));
    }

    private static boolean less(int i, int j) {
        return i < j;
    }

    private static void exch(int[] a, int j) {
        int temp = a[j-1];
        a[j-1] = a[j];
        a[j] = temp;
    }
}

希尔排序(shell):

为了加快速度简单的改进了插入排序 
h有序数组:数组中任意间隔为h的元素都是有序的。h公因子的选择
public class 希尔排序 {
    public static void main(String[] args) {
        int array[] = {3, 11, 5, 8, 3, 2, 456, 3, 2, 8, 9, 98, 77, 1, 58, 91};
        System.out.println(Arrays.toString(array));
        int N = array.length;
        int h = N/2;
        int temp;
        while (h >= 1) {
            for (int i = h; i < N; i++) {
                for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
                    temp = array[j - h];
                    array[j - h] = array[j];
                    array[j] = temp;
                }
            }
            System.out.println();
            h = h / 2;
        }
    }
}
//公因子为3的shell排序, h=3*h+1
class A {
    public static void main(String args[]) { // Sort a[] into increasing order.
        int a[] = {3, 11, 5, 8, 3, 2, 456, 3, 2, 8, 9, 98, 77, 1, 58, 91};
        int N = a.length;
        int h = 1;
        int temp;
        while (h < N / 3) h = 3 * h + 1;
        // 1, 4, 13, 40, 121, 364, 1093, ...
        while (h >= 1) {
            for (int i = h; i < N; i++) {
                // Insert a[i] among a[i-h], a[i-2*h], a[i-3*h]... .
                for (int j = i; j >= h && a[j] < a[j - h]; j -= h) {
                    temp = a[j - h];
                    a[j - h] = a[j];
                    a[j] = temp;
                }

            }
            System.out.println(Arrays.toString(a));
            h = h / 3;
        }
        System.out.println(Arrays.toString(a));
    }
}

归并排序:

归并排序:将一个数组递归的分成两半排序,然后将结果归并起来
 口诀:
 左完必取右
 右完必取左
 谁小就取谁
 取谁谁必增
//将两个有序的子数列合并,原地归并
public class 归并排序 {
    public static void main(String[] args) {
        int a[] = {3, 99, 5, 8, 11, 2, 2, 4, 8, 456};
//        int a[] = {1};
        int N = a.length;
        int aux[] = new int[N];
        int low = 0;
        int high = N - 1;
        int mid = low + (high - low) / 2;

        int i = low;
        int j = mid + 1;
        for (int k = low; k < N; k++) aux[k] = a[k];
        for (int k = low; k < N; k++) {
            if (i > mid) {
                a[k] = aux[j++];
            } else if (j > high) {
                a[k] = aux[i++];
            } else if (aux[j] > aux[i]) {
                a[k] = aux[i++];
            } else {
                a[k] = aux[j++];
            }
        }
        System.out.println(Arrays.toString(a));
    }
}

//自顶向下的归并
class Merge {
    private static int[] aux;

    private static void sort(int[] a) {
        aux = new int[a.length];
        sort(a, 0, a.length - 1);
    }

    private static void sort(int[] a, int low, int high) {
        if (high <= low) return;//递归的出口
        int mid = low + (high - low) / 2;
        sort(a, low, mid);
        sort(a, mid + 1, high);
        merge(a, low, high, mid);

    }

    private static void merge(int[] a, int low, int high, int mid) {
        int i = low;
        int j = mid + 1;
        for (int k = low; k <= high; k++) {
            aux[k] = a[k];
        }
        for (int k = low; k <= high; k++) {
            if (i > mid) a[k] = aux[j++];
            else if (j > high) a[k] = aux[i++];
            else if (aux[i] < aux[j]) a[k] = aux[i++];
            else a[k] = aux[j++];
        }
    }

    public static void main(String[] args) {
        int a[] = {3, 99, 5, 8, 11, 2, 2, 4, 8, 456};
        sort(a);
        System.out.println(Arrays.toString(a));
    }

}

//自底向上的归并,一一合,两两合,四四合……(迭代)
/*
mergeBU的顺序:
sz=1 c=0
merge(a,0,0,1)
merge(a,2,2,3)
merge(a,4,4,5)
merge(a,6,6,7)
merge(a,8,8,9)

merge(a,0,1,3)
merge(a,4,5,7)

merge(a,0,3,7)

merge(a,0,7,9)
 */
class MergeBU {
    private static int[] aux;

    private static void sort(int[] a) {
        int N = a.length;
        aux = new int[a.length];
        //sort(left);
        //sort(right);
        //merge(left,right)
        //sz为子数组的大小(即步长),id为子数组的索引,id是low,id+sz-1就是要合并子数组的mid,id+2sz-1就是high,但是high最大不能超过N-1。
        //现在一个left或者一个right就是一个步长,所以mid和high的计算就不言而喻的。可以画图帮助理解。
        for (int sz = 1; sz < N; sz *= 2) {//按照合并的规则,合并的数组大小为1,2,4,2^n
            for (int id = 0; id < N - sz; id += 2 * sz) {
                merge(a, id, sz + id - 1, Math.min(id + 2 * sz - 1, N - 1));
                System.out.println("merge(" + "a" + "," + id + "," + (sz + id - 1) + "," + Math.min(id + 2 * sz - 1, N - 1) + ")");
            }
            System.out.println();
        }


    }

    private static void merge(int[] a, int low, int mid, int high) {
        int i = low;
        int j = mid + 1;
        for (int k = low; k <= high; k++) {
            aux[k] = a[k];
        }
        for (int k = low; k <= high; k++) {
            if (i > mid) a[k] = aux[j++];
            else if (j > high) a[k] = aux[i++];
            else if (aux[i] < aux[j]) a[k] = aux[i++];
            else a[k] = aux[j++];
        }
    }

    public static void main(String[] args) {
        int a[] = {3, 99, 5, 8, 11, 2, 2, 4, 8, 456};
        sort(a);
        System.out.println(Arrays.toString(a));
    }
}

快速排序:

归并排序是将两个分别有序的数组归并使其有序,而快排是将两个有序数组分别有序时,整个数组便是有序的。
可以理解为分区,左区子数组都是小元素,中区都是重复中元素,右区都是大元素。当这三个区分别有序时,整个数组便都是有序的。
public class 快速排序 {
    public static void main(String[] args) {
        int a[] = {3, 99, 5, 11, 11, 78, 11, 4, 11, 456};
        sort(a);
        System.out.println(Arrays.toString(a));
    }

    public static void sort(int a[]) {
        //这里应该在shuffle下,使得切分更加的平衡。
        sort(a, 0, a.length - 1);
    }

    private static void sort(int[] a, int low, int high) {
        if (low >= high) return;
        int result = partition(a, low, high);
        sort(a, low, result);
        sort(a, result + 1, high);
    }

    private static int partition(int[] a, int low, int high) {
        int i = low;
        int j = high + 1;
        while (true) {
            //当数组有重复的元素出现时,要注意“=”
            while (a[low] >= a[++i]) if (i == high) break;//从左往右找比他大的
            while (a[low] <= a[--j]) if (j == low) break;//从右往左找比他小的
            if (i >= j) break;
            exch(a, i, j);
        }
        exch(a, low, j);//当i和j相遇的时候,交换low和j的位置,此时a[j]就是中间值,左边的都比他小,右边的都比他大
        return j;

    }

    private static void exch(int[] a, int i, int j) {
        int temp = a[j];
        a[j] = a[i];
        a[i] = temp;
    }

}

//主要用于重复元素较多时的排序
class 三向切分法{
    public static void main(String[] args) {
        int[] a = {3, 99, 5, 11, 11, 78, 11, 4, 11, 456};
        sort(a, 0, a.length-1);
        System.out.println(Arrays.toString(a));
    }

    private static void sort(int[] a, int low, int high) {
        if(high<=low) return;
        int lt = low;
        int i = low+1;
        int gt = high;
        int v = a[low];
        while (i<=gt){
            int comp = a[i] - v;//a[low]必须写在while循环的外面,因为这个三向切分法算法中牵扯到low位置值得交换。
            System.out.println(v + " " + a[low]);
            if(comp<0) exch(a, lt++, i++);
            else if(comp>0) exch(a,i,gt--);
            else i++;
        }
        sort(a,low,lt-1);
        sort(a,gt+1,high);
    }

    private static void exch(int[] a, int lg, int i) {
        int  temp = a[i];
        a[i] = a[lg];
        a[lg] = temp;
    }
}

优先队列排序

利用优先队列进行排序,将所有元素传入一个查找最小元素的优先队列,然后重复调用删除最小元素的操作来将他们按顺序删去,就达到了排序的目的
在这重点掌握堆排序
/**
 * 堆排序:
 * 1.初始化堆(在此过程中将其转化为堆有序) 堆有序:当一颗二叉树的每个结点都大于等于它的两个子节点时,它被称为堆有序
 * 2.sink每一个元素
 * 先将其转化为有序堆,会使得后面的排序更加迅速
 * 注意:一。当然也可以遍历每个元素并进行sink,类似于插入排序,但是这样的效率是很慢的。
 *      二。要区分从0开始还是从1开始。
 */
class{
    public static void main(String[] args) {
        int n = 10;
        int[] a = new int[n];
        Random r = new Random();
        for (int i = 0; i < n; i++) {
            a[i] = r.nextInt(1000);
        }
        System.out.println(Arrays.toString(a));
        sort(a);
        System.out.println(Arrays.toString(a));
    }

    private static void sort(int[] a) {
        //1.先转化为堆有序
        int N = a.length-1;
/*        for (int k = N/2; k >=0; k--) {
            sink(a,k,N);
        }*/
        System.out.println(Arrays.toString(a));
        //下沉
        while (N > 0) {
            exch(a, 0, N--);
            sink(a, 0, N);
        }
    }

    private static void exch(int[] a, int k, int i) {
        int temp;
        temp = a[k];
        a[k] = a[i];
        a[i] = temp;
    }

    private static void sink(int[] a, int k, int n) {
        while(2*k+1 <= n){
            int j = 2*k+1;
            if(j< n  && a[j]<a[j+1])  j++; //j<n是关键中的关键
            if (!(a[k] < a[j])) break;
            exch(a, k, j);
            k = j;
        }
    }
}

//针对于从a[1]开始的堆(1.是为了方便 2.a[0]有时候可以做哨兵)
class 上浮下沉{
    private static void swim(int k){
        int a[] = {};
        int j = k / 2;
        while(k>1 && a[k]>a[j]){
            exch(a,k,j);
        }
    }
    private static void sink(int k,int N){
        int a[] = {};
        while (2*k<=N){
            int j = 2*k;
            if(j<N && a[j]<a[j+1]) j++;
            if(a[k]<a[j]) break;
            exch(a,k,j);
            k = j;
        }
    }

    private static void exch(int[] a, int k, int j) {
        int temp = a[k];
        a[k] = a[j];
        a[j] = temp;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值