常见八大排序算法

发布于:2024-10-17 ⋅ 阅读:(7) ⋅ 点赞:(0)

今天我们带来数据结构中常见的8大排序算法。

排序算法 平均时间复杂度 最好情况 最坏情况 空间复杂度 稳定性
冒泡排序 O(n方) O(n方) O(n方) O(1) 稳定
插入排序 O(n方) O(n方) O(n方) O(1) 稳定
选择排序 O(n方) O(n方) O(n方) O(1) 不稳定
希尔排序 O(n1.3方到1,5方) O(n) O(n方) O(1) 不稳定
堆排序 O(n log n) O(n log n) O(n log n) O(1) 不稳定
快速排序 O(n log n) O(n log n)

O(n方)

O(n log n) 不稳定
归并排序 O(n log n) O(n log n) O(n log n) O(n) 稳定
计数排序 O(n + k) O(n + k) O(n + k) O(k) 不稳定

一,冒泡排序

思路:1,从头到尾比较相邻的元素,2,重复第一步n-1次

代码实现:

public void BubbleSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        for (int i = 0; i < str.length; i++) {
            for (int j = 0; j < str.length-1-i; j++) {
                if(str[j]<str[j+1]){
                    swap(str,j,j+1);
                }
            }
        }
        System.out.println(Arrays.toString(str));
    }

swap是交换,

private void swap(int[] str,int i,int j){
        int tmp = str[i];
        str[i] = str[j];
        str[j] = tmp;
    }

代码优化: 优化也不会优化到多好基本还是O(n方的复杂度)

 public void BubbleSortLevel(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        for (int i = 0; i < str.length; i++) {
            boolean a = false;
            for (int j = 0; j < str.length-1-i; j++) {
                if(str[j]<str[j+1]){
                    swap(str,j,j+1);
                    a = true;
                }
            }
            if(!a){
                break;
            }
        }
        System.out.println(Arrays.toString(str));
    }

二,插入排序

思路; 1,定义两个下标i,j,tmp,i从1开始向后遍历,把初始的下标值赋给tmp 2,j每次从i前面开始向前遍历,比较j下标的元素和tmp的值。

代码实现:

public void InsertSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        int j=0;
        int tmp=0;
        for (int i = 1; i < str.length; i++) {
            tmp = str[i];
            for (j = i-1; j >=0 ; j--) {
                if(str[j]<tmp){
                    str[j+1] = str[j];
                }
                else {
                    break;
                }
            }
            str[j+1] = tmp;
        }
        System.out.println(Arrays.toString(str));
    }

三,选择排序

思路: 1,定义两个下标i,j;i从左向右遍历:2,我们创建一个tmpIndex记录i下标的值,j每次都在i的左边,与tmpIndex的值进行比较,记录新的tmpIndex的值,与i下标交换,重复这个步骤。

代码实现:

public void ChooseSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        int j= 0;
        int tmpIndex = 0;
        for (int i = 0; i < str.length; i++) {
            tmpIndex = i;
            for (j = i+1; j < str.length; j++) {
                if(str[j]<str[tmpIndex]){
                    tmpIndex = j;
                }
            }
            swap(str,i,tmpIndex);
        }
        System.out.println(Arrays.toString(str));
    }

四,希尔排序

思路: 希尔排序实际就是多次进行快速排序,但是我们每次是不同的几组数进行排序,我们初始一个gap,gap的取值不一,我们一数组长度/2来赋给gap,每次相邻为gap的元素进行插入排序,再对gap/2,直到gap为1,我们的思路是插入排序对越有序的数组排序越有序

代码实现: 

    public void ShellSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        int gap = str.length/2;
        while (gap>=1){
            ShellSort__InsertSort(str,gap);
            gap/=2;
        }
        System.out.println(Arrays.toString(str));
    }
    private void ShellSort__InsertSort(int[] str,int gap){
        int tmp = 0;
        int j = 0;
        for (int i = gap; i < str.length; i++) {
            tmp = str[i];
            for (j = i-gap; j >= 0; j-=gap) {
                if(str[j]<tmp){
                    str[j+gap] =str[j];
                }
                else {
                    break;
                }
            }
            str[j+gap] = tmp;
        }
    }

五,堆排序

思路: 以升序为例,降序建小根堆,升序建大根堆,

1,建堆  2,栈顶元素与尾元素互换,再进行向下调整  3,直到重复步骤2直到0下标。

代码实现: 

public void HeapSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        CreateHeap(str);
        for (int i = str.length-1; i >=0 ; i--) {
            swap(str,i,0);
            ShiftDown(str,0,i);
        }
        System.out.println(Arrays.toString(str));
    }

    private void CreateHeap(int[] str){
        int c = str.length-1;
        int p = (c-1)/2;
        while (p>=0){
            ShiftDown(str,p,str.length);
            p--;
        }
        System.out.println(Arrays.toString(str));
    }

    private void ShiftDown(int[] str, int parent,int usdSize){
        int child = 2*parent+1;
        while (child<usdSize){
            if(child+1<usdSize && str[child]<str[child+1]){
                child++;
            }
            if(str[child]>str[parent]){
                swap(str,child,parent);
                parent = child;
                child = 2*parent+1;
            }
            else {
                break;
            }
        }
    }

六,快速排序

思路: 1,选择一个基准,定义两个下标,一个从右往左走(先走),一个从左往右走,右边遇到小于基准的与左边大于基准的交换,

2,找到基准,从基准左边和右边递归,重复1的过程。

代码实现(递归实现):

public void QuickSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        QuickSortChild(str,0,str.length-1);
        System.out.println(Arrays.toString(str));
    }
    private void QuickSortChild(int[] str,int start,int end){
        if(start>end){
            return;
        }
        int left = start;
        int right = end;
        int part = partition(str,left,right);
        QuickSortChild(str,start,part-1);
        QuickSortChild(str,part+1,end);
    }
    private int partition(int[] str,int start,int end){
        int left = start;
        int right = end;
        int cmp = str[left];
        while (left<right){
            while (left<right && str[right]<=cmp){
                right--;
            }
            while (left<right && str[left]>=cmp){
                left++;
            }
            if(left<right){
                swap(str,left,right);
            }
        }
        swap(str,start,left);
        return left;
    }

代码优化(递归实现):(三数取中法

public void QuickSort2(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        QuickSortChild(str,0,str.length-1);
        System.out.println(Arrays.toString(str));
    }
    private void QuickSortChild2(int[] str,int start,int end){
        if(start>end){
            return;
        }
        int left = start;
        int right = end;
        int mid = middle(left,(left+right)/2,right);
        swap(str,start,mid);
        int part = partition(str,left,right);
        QuickSortChild(str,start,part-1);
        QuickSortChild(str,part+1,end);
    }
    private int partition2(int[] str,int start,int end){
        int left = start;
        int right = end;
        int cmp = str[left];
        while (left<right){
            while (left<right && str[right]<=cmp){
                right--;
            }
            while (left<right && str[left]>=cmp){
                left++;
            }
            if(left<right){
                swap(str,left,right);
            }
        }
        swap(str,start,left);
        return left;
    }
    private int middle(int left,int middle,int right){
        int[] arr = new int[]{left,middle,right};
        Arrays.sort(arr);
        return arr[1];
    }

 代码实现(非递归实现):

public void QuickSort3(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        QuickSortChild3(str,0,array.length-1);
        System.out.println(Arrays.toString(str));

    }
    private void QuickSortChild3(int[] str,int start,int end){
        Deque<Integer> stack = new ArrayDeque<>();
        int part = partition3(str,start,end);
        if (part+1<end){
            stack.push(end);
            stack.push(part+1);
        }
        if(part-1>start){
            stack.push(part-1);
            stack.push(start);
        }
        while (!stack.isEmpty()){
            end = stack.pop();
            start = stack.pop();
            part = partition3(str,start,end);
            if (part+1<end){
                stack.push(end);
                stack.push(part+1);
            }
            if(part-1>start){
                stack.push(part-1);
                stack.push(start);
            }
        }
    }

    private int partition3(int[] str,int start,int end){
        int left = start;
        int right = end;
        int cmp = str[left];
        while (left<right){
            while (left<right && str[right]<=cmp){
                right--;
            }
            while (left<right && str[left]>=cmp){
                left++;
            }
            if(left<right){
                swap(str,left,right);
            }
        }
        swap(str,start,left);
        return left;
    }

七,归并排序

思路: 1,我们把数据平均分为两个部分定义左中右三个下标,左边递归,右边递归,

2,当左下标大于等于右递下标归停止,我们使用合并数组的方法,把每层递归后有序的左右子树有序化

代码实现:

public void MergeSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        MergeSortChild(str,0,str.length-1);
        System.out.println(Arrays.toString(str));

    }

    private void MergeSortChild(int[] str,int left, int right){
        if(left>=right){
            return;
        }
        int mid = (left+right)/2;
        MergeSortChild(str,left,mid);
        MergeSortChild(str,mid+1,right);

        MergeSort__new(str,left,mid,right);
    }
    private void MergeSort__new(int[] str,int left,int mid,int right){
        int s1 = left;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = right;
        int[] arr = new int[right-left+1];
        int i=0;
        while (s1<=e1 && s2<=e2){
            if(str[s1]<=str[s2]){
                arr[i] = str[s1];
                i++;
                s1++;
            }
            if(str[s2]<str[s1]){
                arr[i] = str[s2];
                i++;
                s2++;
            }
        }
        while (s1<=e1){
            arr[i] = str[s1];
            i++;
            s1++;
        }
        while (s2<=e2){
            arr[i] = str[s2];
            i++;
            s2++;
        }

        for (int k = 0; k < i; k++) {
            str[k+left] = arr[k];
        }
    }

 

八,计数排序

计数排序适合排那些一定范围的大量数据,比如1-100的考试成绩

思路: 1,我们遍历原数组,找出最大值最小值,用他们的差值大小构建一个计数数组,

2,把原数组出现的数字-min放到计数数组里,有一个计数数组就加一,循环遍历计数数组,直到计数数组全部元素都为0

代码实现: 

public void CountIngSort(int[] array){
        int[] str = Arrays.copyOf(array,array.length);
        int max = str[0];
        int min = str[0];
        for (int i = 0; i <str.length ; i++) {
            if(str[i]>max){
                max = str[i];
            }
            if(str[i]<min){
                min = str[i];
            }
        }
        int[] count = new int[max-min+1];

        for (int i = 0; i < str.length; i++) {
            int a = str[i];
            count[a-min]+=1;
        }
        int j = 0;
        int i = 0;
        while (i<count.length) {
            while (count[i]!=0){
                str[j] = i+min;
                j++;
                count[i]--;
            }
            i++;
        }
        System.out.println(Arrays.toString(str));
    }