数据结构:常考排序算法整理

65 阅读6分钟

常见排序算法

插入排序:直接插入排序、希尔排序

选择排序:选择排序、堆排序

交换排序:冒泡排序、快速排序

归并排序:归并排序

插入排序:需要从前往后进行扫描,扫描到的每个数都需要和前面的所有数进行比较,然后把这个数放在合适的位置。

1.gif

时间复杂度:最优全部排好了O(n),最差情况全部进行排序O(n^2)

代码实现:

public class 直接插入排序 {
    public static void main(String[] args) {
        int [] arr = {38,65,97,76,13,27,49};
        arr = insertionSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] insertionSort(int[] arr){
        int n = arr.length;
        for(int i =1;i<n;i++){
            int current = arr[i];
            int j = i-1;
            while(j>=0 && arr[j] > current){
                arr[j+1]= arr[j];
                j--;
            }
            arr[j+1] = current;
        }
        return arr;
    }
}

希尔排序:有一个长度为N的数组a,选定一个小于N的整数,然后将数组a拆分,从第一个元素开始将第一个元素和第N+N/a进行比较,然后交换顺序,然后再对该序列进行一次插入排序,然后在选取比上一个增量小的整数作为第二增量,直到递减为1。

相对于直接插入排序,更快些:因为通过大步移动和局部排序,将时间复杂度有了进一步提升

希尔排序.gif

时间复杂度:介于O(nlongn)和O(n^2)之间,做到了对直接插入排序的优化

代码实现:


public class 希尔排序 {
    public static void main(String[] args) {
        int [] arr = {38,65,97,76,13,27,49};
        arr = shellSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] shellSort(int[] arr){
        int n = arr.length;
        for(int gap = n/2;gap>0;gap/=2){
            for(int i = gap;i<n;i++){
                int current = arr[i];
                int j = i-gap;
                while(j>=0 && arr[j] > current){
                    arr[j+gap] = arr[j];
                    j-= gap;
                }
                arr[j+=gap] = current;
            }
        }
        return arr;
    }
}

选择排序:每次从待排序的中选择最小值,然后和序列起始位置进行交换,直到全部待排序数组排序完

选择排序.gif

时间复杂度:最坏最好情况都是O(N^2)

代码实现:


public class 选择排序 {
    public static void main(String[] args) {
        int[] arr = {10,9,8,7,6,5,1,3,4};
        arr = selectSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] selectSort(int[] arr){
        int n = arr.length;
        for(int i = 0;i<n-1;i++){
            int min = i;
            for(int j = i+1;j<n;j++){
                if(arr[j] < arr[min]){
                    min = j;
                }
            }
            int temp = arr[i];
            arr[i] = arr[min];
            arr[min] = temp;
        }
        return arr;
    }
}

堆排序:分为大根堆和小根堆,根是对于根节点来说的,大根堆是正序,小根堆是逆序

如图演示大顶堆构建,首先创建大顶堆堆,然后通过向上调整算法去实现大顶堆

堆排序 (1).gif

实现流程:通过向下调整算法和向上调整算法来分别实现构建小堆和键大堆

时间复杂度:建堆的时间复杂度O(N),向上/向下调整算法的时间复杂度是O(log2N),所以时间复杂度是O(N*log2N)

大顶堆代码实现:

public class 堆排序 {
    //构建大顶堆
    //然后调整大顶堆
    //然后交换首位顺序即可
    public static void main(String[] args) {
        int [] arr = {38,65,97,76,13,27,49};
        arr = heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] heapSort(int arr[]){
        int n = arr.length;
        buildMaxHeap(arr,n);

        for(int i =n-1;i>0;i--){
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;

            adjustheap(arr,i,0);
        }

        return arr;
    }

    public static void adjustheap(int []arr,int n ,int i){
        int largest = i;
        int left = 2*i+1;
        int right= 2*i+2;

        if(left<n && arr[left] > arr[largest]){
            largest = left;
        }
        if(right<n && arr[right] > arr[largest]){
            largest = right;
        }

        if(largest != i){
            int swap = arr[i];
            arr[i] = arr[largest];
            arr[largest] = swap;

            adjustheap(arr,n,largest);
        }
    }

    public static void buildMaxHeap(int[] arr,int n){
        for(int i = n/2-1;i>=0;i--){
            adjustheap(arr,n,i);
        }
    }
}

小顶堆实现代码:

public static int[] headsortmin(int[] arr){
    int n = arr.length;
    buildminheap(arr,n);

    for(int i = n-1;i>0;i--){
        int temp = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;

        adujustminheap(arr,i,0);
    }
    return arr;
}
public static void buildminheap(int[] arr,int n){
    for(int i = n/2-1;i>=0;i--){
        adujustminheap(arr,n,i);
    }
}
public static void adujustminheap(int[] arr,int n,int i){
    int min = i;
    int left = 2*i+1;
    int right = 2*i+2;

    if(left<n && arr[left]<arr[min]){
        min = left;
    }

    if(right<n && arr[right]<arr[min]){
        min = right;
    }

    if(min != i){
        int temp = arr[min];
        arr[min] = arr[i];
        arr[i] = temp;

        adujustminheap(arr,n,min);
    }
}

冒泡排序:通过一次排序,求最大最小值,每次将最大值或者最小值放在符合的对应位置

冒泡排序.gif

时间复杂度:最优O(N),最差情况O(N^2)

代码实现:


public class 冒泡排序 {
    public static void main(String[] args) {
        int[] arr= {8,5,6,4,9,10};
        arr = bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }

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

快速排序:选出一个基准值,让小于它的元素放在左边,大于它的元素在右边,然后依次再对左边部分进行同样操作,选取一个基准值然后进行分配,直至左边已排好顺序,然后去排序右边

快速排序 (1).gif

时间复杂度;为O(nlogn),最坏的情况时间复杂度为O(n^2)

代码实现:其实思想就是借助两个指针,也就是代码中for循环中的i和pointer


public class 快速排序 {
    //选取基数值,借助两个指针
    //选取第一个大于该基数的值,然后去寻找小于该基数的值,然后交换两者位置,然后将指向第一个
    //基数值的指针++,继续重复上述操作,当两个指针碰了面,直接交换第一个指针最初指向的值,然后交换两者
    public static void main(String[] args) {
        int [] arr = {38,65,97,76,13,27,49};
        arr = quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] quickSort(int[] arr,int low,int high){
        if(low < high){
            //先划分子数组的位置
            int position = partition(arr,low,high);
            quickSort(arr,low,position-1);
            quickSort(arr,position+1,high);
        }
        return arr;
    }
    public static int partition(int []arr, int low,int high){
        //选取中心元素

        int pivot = arr[high];
        int pointer = low;
        //通过i和pointer来当做指针,和基数值进行比较
        //将小于的放在左边,大于的放在右边
        for(int i =low;i<high;i++){
            if(arr[i] <= pivot){
                int temp = arr[i];
                arr[i] = arr[pointer];
                arr[pointer] = temp;
                pointer++;
            }
        }
        //然后小于的在一边,arr[pointer]值左边,大于的在pointer右边,当i到high处没有小于arr[high]的值了,
        //直接交换arr[pointer] 和arr[high],就可以做到小于的在左边,大于在右边
        int temp = arr[pointer];
        arr[pointer] = arr[high];
        arr[high] =temp;

        return pointer;
    }
}

归并排序:将序列分成两个长度相等的子序列,然后不断去裂化,当每个子序列只有一个数据时,然后对子序列进行归并,然后依次去不断合并两个子序列

归并排序.gif

时间复杂度: O(nlogn)

代码实现:和快速排序都是分而治之的思想


public class 归并排序 {
    //首先先分组
    //然后再合并
    public static void main(String[] args) {
        int [] arr = {38,65,97,76,13,27,49};
        arr = mergeplay(arr);
        System.out.println(Arrays.toString(arr));

    }
    public static int[] mergeplay(int[] nums){
        if(nums == null || nums.length == 1){
            return nums;
        }
        nums = mergeSort(nums,0,nums.length-1);
        return nums;
    }
    public static int[] mergeSort(int[] arr,int left,int right){
        if(left>= right){
            return arr;
        }
        int mid = left+(right-left)/2;
        mergeSort(arr,left,mid);
        mergeSort(arr,mid+1,right);
        merge(arr,left,mid,right);

        return arr;
    }
    public static void merge(int[] nums,int left,int mid,int right){
        int [] temp = new int[right-left+1];
        int i = left,j = mid+1 ,k = 0;

        while(i<= mid && j<= right){
            if(nums[i] <= nums[j]){
                temp[k++] = nums[i++];
            }else{
                temp[k++] = nums[j++];
            }
        }

        while(i <= mid){
            temp[k++] = nums[i++];
        }

        while(j <= right){
            temp[k++] = nums[j++];
        }

        System.arraycopy(temp,0,nums,left,temp.length);

    }

}

如果有错误,欢迎指正,创作不易,如果对您有用,留下个赞吧,感谢支持