排序算法总结


更正:

(1)快速排序的空间复杂度:最好/平均情况:O(logn)  最坏情况:O(n)

(2)希尔排序的时间复杂度与增量序列的选择有关。

时间复杂度:可以认为是对排序数据总的操作次数,反映当n变化时,操作次数呈现的规律。

空间复杂度:指算法在计算机内执行时所需存储空间的度量,也表现为n的函数。

算法稳定性:假设在数组中存在a[i] = a[j],若在排序之前,a[i]在a[j]的前面。排序之后,a[i]仍然在a[j]的前面。则这个算法就是稳定的。

动图演示:https://www.cnblogs.com/onepixel/articles/7674659.html

1. 冒泡排序

public class BubbleSort {
    public void bubbleSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        int N = data.length;
        boolean didSwap = false;
        for (int i = 0; i < N - 1; i++) {
            for (int j = 0; j < N - 1 - i; j++) {
                if (data[j] > data[j + 1]) {
                    swap(data, j, j + 1);
                    didSwap = true;
                }
            }
            if (!didSwap) return;
        }
    }

    private void swap(int[] data, int i, int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }

    public static void main(String[] args) {
        BubbleSort bubble = new BubbleSort();
        int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
        bubble.bubbleSort(data);
        System.out.println(Arrays.toString(data));
    }
}

2. 快速排序

快速排序(Quick Sort)使用分治法策略。它的基本思想是:选择一个基准元素,通过一趟排序将待排序的数据分成独立的两部分。其中一部分的所有数据都比另一部分的所有数据要小。然后,再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据序列变成有序的。

public class QuickSort {
    public void quickSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        quickSort(data, 0, data.length - 1);
    }

    private void quickSort(int[] data, int start, int end) {
        if (start >= end ) {
            return;
        }
        int pivotIndex = partition(data, start, end); //基准元素的位置
        quickSort(data, start, pivotIndex - 1);
        quickSort(data, pivotIndex + 1, end);
    }

    private int partition(int[] data, int start, int end) {
        int i = start, j = end;
        int pivotKey = data[i]; //基准元素的值
        while (i < j) {
            while (i < j && data[j] >= pivotKey)
                j--;
            if (i < j)
                data[i++] = data[j];
            while (i < j && data[i] <= pivotKey)
                i++;
            if (i < j)
                data[j--] = data[i];
        }
        data[i] = pivotKey;
        return i;
    }

    public static void main(String[] args) {
        QuickSort quick = new QuickSort();
        int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
        quick.quickSort(data);
        System.out.println(Arrays.toString(data));
    }
}

3. 直接插入排序

基本思想:把n个待排序的元素看成一个有序表和一个无序表。开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。

public class InsertSort {
    public void insertSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        int N = data.length;
        for (int i = 1; i < N; i++) {
            int insertValue = data[i];
            int j = i - 1;
            while (j >= 0 && insertValue < data[j]) {
                data[j + 1] = data[j];
                j--;
            }
            data[j+1] = insertValue;
        }
    }

    public static void main(String[] args) {
        InsertSort insert = new InsertSort();
        int[] data = {38, 65, 97, 76, 13, 27, 49};
        insert.insertSort(data);
        System.out.println(Arrays.toString(data));
    }
}

4. 希尔排序(缩小增量排序)

它的基本思想:对于n个待排序的数列,取一个小于n的整数increment(增量)将待排序元素分成若干组子序列,所有距离第一个元素(下标为0)为increment的倍数的记录放在同一个组中。然后,对各组中的元素进行直接插入排序。之后减小increment的值,并重复执行上述的分组和排序。最后一个增量等于1,完成排序过程。

public class ShellSort {
    public void shellSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        int N = data.length;
        for (int increment = N / 2; increment > 0; increment /= 2) {
            for (int i = increment; i < N; i++) {
                int tempValue = data[i];
                int j = i - increment;
                while (j >= 0 && tempValue < data[j]) {
                    data[j + increment] = data[j];
                    j = j - increment;
                }
                data[j + increment] = tempValue;
            }
        }
    }

    public static void main(String[] args) {
        ShellSort shell = new ShellSort();
        int[] data = {38, 65, 97, 76, 13, 27, 49};
        shell.shellSort(data);
        System.out.println(Arrays.toString(data));
    }
}

5. 简单选择排序

public class SelectSort {
    public void selectSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        int N = data.length;
        for (int i = 0; i < N; i++) {
            int minValue = data[i];
            int minIndex = i;
            for (int j = i + 1; j < N; j++) {
                if (data[j] < minValue) {
                    minValue = data[j];
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                data[minIndex] = data[i];
                data[i] = minValue;
            }
        }
    }

    public static void main(String[] args) {
        SelectSort select = new SelectSort();
        int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
        select.selectSort(data);
        System.out.println(Arrays.toString(data));
    }
}

6. 堆排序

堆排序是指利用堆(完全二叉树)这种数据结构所设计的一种排序算法,比较适合于数据量非常大的场合。而快速排序与归并排序是基于递归实现的,所以在数据量非常大时会发生堆栈溢出错误。

堆分为“最大堆”和“最小堆”。最大堆通常用于进行“升序”排序,而最小堆通常用于进行“降序”排序。

基本思想:将待排序的序列构造成一个最大堆。此时,整个序列的最大值就是堆顶的根节点,将其与数组的末尾元素交换,此时末尾元素就是最大值。然后,将剩余的n-1个序列重新构造成一个堆,再与数组中倒数第二个元素交换。如此反复执行,就能得到一个有序的序列。即:

(1)初始化最大堆

(2)输出堆顶元素,调整剩余元素成为一个新的最大堆

数组实现的二叉堆的性质:

性质一:索引为i的节点的左子节点的下标为 (2*i + 1);

性质二:索引为i的节点的右子节点的下标为 (2*i + 2);

性质三:索引为i的节点的父节点的下标为 floor((i-1) / 2)。

public class HeapSort {
    public void heapSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        int N = data.length;
        for (int i = N/2 - 1; i >= 0; i--) {
            adjustSort(data, i, N-1);
        }
        for (int i = N-1; i > 0; i--) {
            swap(data, 0, i);
            adjustSort(data, 0, i-1);
        }

    }

    private void adjustSort(int[] data, int start, int end) {
        if (start >= end) {
            return;
        }
        int index = start;
        int value = data[index];
        for (int i = 2 * index + 1; i <= end; i = 2 * i + 1) {
            if (i < end && data[i] < data[i+1]) {
                i++;
            }
            if (value >= data[i]) {
                break;
            } else {
                swap(data, index, i);
                index = i;
            }
        }
    }

    private void swap(int[] data, int i, int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }

    public static void main(String[] args) {
        HeapSort heap = new HeapSort();
        int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
        heap.heapSort(data);
        System.out.println(Arrays.toString(data));
    }
}

7. 归并排序

归并排序就是利用归并的思想对数列进行排序。

public class MergeSort {
    public void mergeSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        mergeSort(data, 0, data.length - 1);
    }

    private void mergeSort(int[] data, int start, int end) {
        if (start >= end) {
            return;
        }
        int mid = (start + end) / 2;
        mergeSort(data, start, mid);
        mergeSort(data, mid + 1, end);
        merge(data, start, mid, end);
    }

    private void merge(int[] data, int start, int mid, int end) {
        int L = end - start + 1;
        int[] temp = new int[L]; //temporary area
        int i = start, j = mid + 1;
        int k = 0; //the index of created temporary area
        while (i <= mid && j <= end) {
            if (data[i] <= data[j]) {
                temp[k++] = data[i++];
            } else {
                temp[k++] = data[j++];
            }
        }
        while (i <= mid) {
            temp[k++] = data[i++];
        }
        while (j <= end) {
            temp[k++] = data[j++];
        }
        System.arraycopy(temp, 0, data, start, L);
    }

    public static void main(String[] args) {
        MergeSort merge = new MergeSort();
        int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
        merge.mergeSort(data);
        System.out.println(Arrays.toString(data));
    }
}

8. 基数排序

public class RadixSort {
    public void radixSort(int[] data) {
        if (data == null || data.length == 0) {
            return;
        }
        int max = getMax(data);
        for (int exp = 1; max/exp > 0; exp *= 10) {
            countSort(data, exp);
        }
    }

    private void countSort(int[] data, int exp) {
        int N = data.length;
        int[] output = new int[N];
        int[] buckets = new int[10];
        for (int i = 0; i < N; i++) {
            buckets[(data[i]/exp)%10]++;
        }
        for (int i = 1; i < 10; i++) {
            buckets[i] += buckets[i - 1];
        }
        for (int i = N - 1; i >= 0; i--) {
            output[buckets[(data[i]/exp)%10] - 1] = data[i];
            buckets[(data[i]/exp)%10]--;
        }
        System.arraycopy(output, 0, data, 0, N);
    }

    private int getMax(int[] data) {
        int max = data[0];
        for (int i = 1; i < data.length; i++) {
            if (data[i] > max) {
                max = data[i];
            }
        }
        return max;
    }

    public static void main(String[] args) {
        RadixSort radix = new RadixSort();
        int[] data = {49, 38, 65, 97, 76, 13, 27, 49};
        radix.radixSort(data);
        System.out.println(Arrays.toString(data));
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值