数据结构 --几大排序算法

dc

插入排序

1直接插入排序----具有稳定性–O(n)-O(n2)

  • 假设第一个元素已经排好序,用需要插入的元素和前面已经排好序的元素比较,找的第一个(强调第一个是为了保证稳定性)小于它的元素,插入到这个元素的前面.
  • 建立在元素基本有序,数据量不大的情况下,

2希尔排序----不具有稳定性-----O(n)-O(n1.3)

​ 最大的时间复杂度是数学上的一个难题,没解决出来,在n为一个稳定的范围时,接近n的1.3次方.

​ 又称缩小增量排序

  • ​ 为了解决数据量比较大,元素无序问题,引入希尔排序,把一个表依据增量序列d划分成若干个子表,先使得这些个子表有序,然后再对全体记录进行一次直接插入排序

直接插入排序


            //插入排序
    public static void InsertSort(int[] A, int n) {
        int j;
        int temp;
        for (int i = 1; i < n; i++) {
            if (A[i] < A[i-1]) {
                temp = A[i];

				//while(A[j]>temp &&j>=0){
                
               		 	//A[j+1] = A[j];
                		//j--
           		 //}
                for (j = i - 1; j >= 0 && A[j] > temp; j--) {
                    A[j+1] = A[j];
                }
                A[j + 1] = temp;
            }
        }

折半直接插入排序O(n)-O(n2)

//折半

        public static void binInsertSort2(int[] A){
        int j =0;

            for (int i = 1; i < A.length; i++) {
                if(A[i]<A[i-1]){
                     int temp = A[i];
                    int low =0;
                    int high = i-1;
                    while (low <= high) {
                        int mid = (low +high) / 2;
                        if(A[mid]>=temp){
                            high = mid -1;
                        }else{
                            low = mid + 1;
                        }
                    }
                    for (j = i-1; j>=low; --j) {
                        A[j+1] = A[j];
                    }
                    //A[j+1]=temp;也行

                    A[low] = temp;
               }
            }

        }


希尔排序

希尔排序----不具有稳定性-----O(n)-O(n1.3)**

​ 又称缩小增量排序

  • ​ 为了解决数据量比较大,元素无序问题,引入希尔排序,把一个表依据增量序列d划分成若干个子表,先使得这些个子表有序,然后再对全体记录进行一次直接插入排序
  //希尔1
    public static void shellSort(int[] A,int n){
        int d ,j,temp = 0;
        for(d=n/2;d>=1;d = d/2){
            //这个 i= d,不等于d+1,和王道不一样,
            for (int i = d; i <n ; i++) {
                if(A[i]<A[i-d]) {
                    temp = A[i];

                    for (j = i - d; j >=0 && A[j] > temp; j = j - d) {
                        A[j + d] = A[j];

                    }
                    A[j + d] = temp;
                }//if

            }

        }






//希尔2
        public static void shell2(int[]A,int n){
        int j;
            for(int d= n/2;d>=1;d= d/2){
                for(int i = d;i<n;i++){
                    if(A[i] <A[i-d]) {
                        int temp = A[i];

                        for (j = i - d; j >= 0 && A[j] > temp;j = j- d){
                            A[j +d] = A[j];
                        }
                        A[j+d] = temp;
                    }
                }

             }
        }

总的插入排序(3个—例子)

package Demo01;

public class demo02 {
    public static void main(String[] args) {
        int[] A = new int[]{21, 3, 54, 4,7, 64,9, 3};
        shellSort(A,A.length);
        for (int a : A
        ) {
            System.out.print(a +",");
        }
    }
            //折半插入排序
    public static void binaryinsertSort(int[] A, int n) {
        int low, high, mid,j;
        for (int i = 1; i < n; i++) {
            if(A[i] <A[i-1]){
                int temp = A[i];
                low = 0;
                high = i-1;

                while (low <= high) {
                    mid = (low + high) / 2;
                    if (temp < A[mid]) {
                        high = mid - 1;
                    } else {
                        low = mid + 1;
                    }
                }
                for (  j = i - 1; j >=high +1; j--) {
                    A[j + 1] = A[j];
                }
                A[j+1] = temp;
            }//if

        }

    }
            //插入排序
    public static void InsertSort(int[] A, int n) {
        int j;
        int temp;
        for (int i = 1; i < n; i++) {
            if (A[i] < A[i-1]) {
                temp = A[i];

                //for (j=i-1;A[j]>temp&&j>=0;j-- ) {


                for (j = i - 1; j >= 0 && A[j] > temp; j--) {
                    A[j+1] = A[j];
                }
                A[j + 1] = temp;
            }
        }
    }
    //希尔
    public static void shellSort(int[] A,int n){
        int d ,j,temp = 0;
        for(d=n/2;d>=1;d = d/2){
            //这个 i= d,不等于d+1,和王道不一样,
            for (int i = d; i <n ; i++) {
                if(A[i]<A[i-d]) {
                    temp = A[i];

                    for (j = i - d; j >=0 && A[j] > temp; j = j - d) {
                        A[j + d] = A[j];

                    }
                    A[j + d] = temp;
                }//if

            }

        }








    }

//插入排序,折半
        public static  void sort(int[] array) {
            int temp;
            int j;

            for (int i = 1; i <array.length; i++) {
                int low = 0;
                int hight = i - 1;
                //这一步的if 是灵魂,我觉得这一步可以省下一些步骤.自创
                if(array[i]<array[i-1]) {
                    temp = array[i];


                    while (hight >= low) {
                        int mid = (low + hight) / 2;
                        if (array[mid] > temp) {
                            hight = mid - 1;
                        } else {
                            low = mid + 1;
                        }
                    }

                    for (j = i - 1; j >= low; --j) {
                        array[j + 1] = array[j];
                    }

                    array[low] = temp;
                }

            }

        }
//折半

        public static void binInsertSort2(int[] A){
        int j =0;

            for (int i = 1; i < A.length; i++) {
                if(A[i]<A[i-1]){
                     int temp = A[i];
                    int low =0;
                    int high = i-1;
                    while (low <= high) {
                        int mid = (low +high) / 2;
                        if(A[mid]>=temp){
                            high = mid -1;
                        }else{
                            low = mid + 1;
                        }
                    }
                    for (j = i-1; j>=low; --j) {
                        A[j+1] = A[j];
                    }

                    A[low] = temp;
               }
            }

        }


//希尔2
        public static void shell2(int[]A,int n){
        int j;
            for(int d= n/2;d>=1;d= d/2){
                for(int i = d;i<n;i++){
                    if(A[i] <A[i-d]) {
                        int temp = A[i];

                        for (j = i - d; j >= 0 && A[j] > temp;j = j- d){
                            A[j +d] = A[j];
                        }
                        A[j+d] = temp;
                    }
                }

             }
        }

}

交换排序

1冒泡排序-----具有稳定性-----o(n)–O(n2)

两辆相比,每次找出最大或者最小的放到最终的位置,

2快排------不具有稳定性

​ 递归每次找出最中间的那个数,放到最终的位置,直到剩余一个或者0个元素.

(1) 时间复杂度: o(n* log2n) —O(n *n)

  • ​ 取决于划分操作的好坏,操作中枢轴的确定等,

  • ​ 后面的log2n -n就是二分查找树的最小高度和最大高度

​ **(2)*空间复杂度, O(log2n)-----O(n)

  • ​ 取决于递归的深度.也就是树的高度,

冒泡排序

概括思路:两两相比 ;每次都使得最大或者最下的元素放到最终的位置;

//增序
public static void bubbleSort(int[] arr ){
        int n = arr.length;
    //这里i---n-1次
        for (int i = 0; i < n-1; i++) {
            boolean flag = false;
            for (int j = n-1; j >i; j--) {
                if (arr[j - 1] > arr[j]) {
                    //swap(arr[j-1],arr[j]);
                    int temp = arr[j-1];
                    arr[j-1] =arr[j];
                    arr[j] = temp;
                }

               flag = true;

            }
           if(flag==false){
                return;
           }
        }

    }

快速排序–划分

pivot:枢轴

partition:分割

总结思路:

​ (1) 基于分治法;

(2)代码写法:

  • ​ 1每次都是先划分为一半;
  • ​ 2在排序;
(3) 思路概括:

​ 每次都使得一个数(枢轴元素)到最终的位置;目的:优先使得最中间的那个数到达最终的位置;相当于每次选择一个枢轴元素;将大于和小于它的数放到它的左边和右边;

/*快排

     */
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            //划分函数
            int pivotpoint = partition (arr,low ,high);
            quickSort(arr, low, pivotpoint - 1);
            quickSort(arr,pivotpoint+1,high);
        }



    }

         //划分个分割函数,使得成每一个子表
    public static int  partition(int[] arr, int low, int high) {
        //定义中枢轴值
        int pivot = arr[low];
        while(low <high) {

            while ( low<high&& arr[high] >= pivot) {
                high--;
            }
            arr[low] = arr[high]; 

            while (low<high&& arr[low]  <=pivot) {
                low++;
            }
            arr[high] = arr[low];

        }
        arr[low] =pivot;

        return low;

    }

总的(2个)

package Demo01;

public class demo03SwapSort {
    public static void main(String[] args) {
        int[] A = new int[]{21, 3, 54, 4, 7, 64, 9, 3};
        //bubbleSort(A);
        quickSort(A,0,A.length-1);
        for (int a : A
        ) {
            System.out.print(a + ",");
        }
    }

    /*
    交换排序----冒泡排序 --递增排序

     */
    //

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

               flag = true;

            }
           if(flag==false){
                return;
           }
        }

    }

    /*快排

     */
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            //划分函数
            int pivotpoint = partition (arr,low ,high);
            quickSort(arr, low, pivotpoint - 1);
            quickSort(arr,pivotpoint+1,high);
        }



    }

         //划分个分割函数,使得成每一个子表
    public static int  partition(int[] arr, int low, int high) {
        //定义中枢轴值
        int pivot = arr[low];
        while(low <high) {

            while ( low<high&& arr[high] >= pivot) {
                high--;
            }
            arr[low] = arr[high];

            while (low<high&& arr[low]  <=pivot) {
                low++;
            }
            arr[high] = arr[low];

        }
        arr[low] =pivot;

        return low;

    }
}

选择排序

1简单选择排序

思路概括:每一趟在待排序中选取关键字最小或者最大的元素加入有序序列的末尾;

  • 时间复杂度:O(n2)

  • 空间复杂度O(1)

  • 满足稳定性

 //简单插入排序

    public  static void slecetSort(int[]arr){
        for (int i = 0; i < arr.length-1; i++) {
            int min = i;
            for (int j = i+1; j < arr.length ; j++) {
                if (arr[j]<arr[min]){
                    min =j;
                }
            }
            if(min !=i){
               swap(arr,i,min);
            }

        }

    }
//交换函数
    public static void swap(int[] arr, int i, int min) {
        int temp= arr[min];
        arr[min]= arr[i];
        arr[i] = temp;

    }

2堆排序

**核心思路:**例如大根堆;(堆顶元素最大)

​ (1)构建初始堆;调整堆成大根堆;利用大根堆的建立过程(最小元素下坠)一直交换堆顶元素和堆低元素;

​ 让堆顶元素下坠;这样每次都会使得一个相对最大的数到堆低;(对于这个堆低最大元素下一次是不用再算到排序的里面的);

​ (2)大根堆的调整过程适合找出前K个最小的前n个数;(每次让a和前n数中组成的大根堆的堆顶比较;若小于堆顶x;则用他代替x)

时间复杂度:

  • 1建立堆—O(4n);
  • 2遍历每个元素则是n-1;之后再heapAdjust()每次不超过树的高度log2n,===>则是(n-1)*log2n= O(nlog2n);
  • 则时间复杂度就是O(4n) + O(n *log2n) =O(nlog2n);

空间复杂度:O(1);

不满足稳定性

代码:

如果从0开始,

  • A.length =len,则倒数第一个是分支节点的是i= len/2-1;从倒数第一个分支节点遍历到第0个节点;
//交换函数
    public static void swap(int[] arr, int i, int min) {
        int temp= arr[min];
        arr[min]= arr[i];
        arr[i] = temp;
        
        
         //堆排序
    /*
    建立大根堆,再排序,让大根堆的顶点和最后一个元素交换,然后让堆顶元素下坠;连续执行,遍历所有数字;
    堆的建立查询等-----完全二叉树的结构(不能是二叉搜索树,因为不会没有左孩子还有右孩子这种现象出现),二次搜索树的顺序的变形.
    --快排的划分思想-----二叉搜索树的查找,
     */


    //建立大根堆
        public  static  void BuildHeap(int[] A, int len) {
        //int lens = A.length1;
            //i 为从下往上看第一个分支节点.从倒数第一个分支节点遍历到第0个节点;
        for (int i = len / 2 -1; i >=0; i--) {
            HeapAdjust(A,i ,len);

        }
    }

    //每次的分支节点向下坠;
    public static void HeapAdjust(int[] A, int k,int len) {
        int temp = A[k];
        /*
        总的思想:i从第一个分支节点,向后面节点比较,一直到<len,即最后一个;
        把第一个分支节点放到它应该放的位置
        */
        //从第一个分支节点,与后面它的子节点比较;
        //之后开始选择这个
        for (int i = 2*k +1; i <len ; i = 2*i+1) {
            if(i +1 <len &&A[i]<A[i+1]){
                i++;
            }
            if(temp >A[i]){
                break;
            }
            A[k]=A[i];
            k =i;
        }
        A[k] =temp;

    }
    //堆排序
    public  static void heapSort(int[] A,int len){
        BuildHeap(A, len);
        //i>0就行, n-1遍就可以了;
        for (int i = len - 1; i >0; i--) {
            swap(A,i,0);
            HeapAdjust(A,0,i);
        }
    }

3总的

package cn.itcast.jdbc;

public class SelcetSort {
    public static void main(String[] args) {
        int[] A = new int[]{43, 23, 35, 54, 1, 2};

        //slecetSort(A);
        heapSort(A,A.length);//堆排序;
        for (int i = 0; i < A.length; i++) {
            System.out.print(A[i] + ";");
        }
    }
    //简单插入排序
    public  static void slecetSort(int[]arr){
        for (int i = 0; i < arr.length-1; i++) {
            int min = i;
            for (int j = i+1; j < arr.length ; j++) {
                if (arr[j]<arr[min]){
                    min =j;
                }
            }
            if(min !=i){
               swap(arr,i,min);
            }

        }

    }
//交换函数
    public static void swap(int[] arr, int i, int min) {
        int temp= arr[min];
        arr[min]= arr[i];
        arr[i] = temp;

    }


    //堆排序
    /*
    建立大根堆,再排序,让大根堆的顶点和最后一个元素交换,然后让堆顶元素下坠;连续执行,遍历所有数字;
    堆的建立查询等-----完全二叉树的结构(不能是二叉搜索树,因为不会没有左孩子还有右孩子这种现象出现),二次搜索树的顺序的变形.
    --快排的划分思想-----二叉搜索树的查找,
     */


    //建立大根堆
        public  static  void BuildHeap(int[] A, int len) {
        //int lens = A.length1;
        for (int i = len / 2 -1; i >=0; i--) {
            HeapAdjust(A,i ,len);

        }
    }

    //每次的分支节点向下坠;
    public static void HeapAdjust(int[] A, int k,int len) {
        int temp = A[k];
        for (int i = 2*k +1; i <len ; i = 2*i+1) {
            if(i +1 <len &&A[i]<A[i+1]){
                i++;
            }
            if(temp >A[i]){
                break;
            }
            A[k]=A[i];
            k =i;
        }
        A[k] =temp;

    }
    //堆排序
    public  static void heapSort(int[] A,int len){
        BuildHeap(A, len);
       
        for (int i = len - 1; i >0; i--) {
            swap(A,i,0);
            HeapAdjust(A,0,i);
        }
    }


}

4找出前k个最大元素,用大根堆的办法;

找出前K个最大的元素,首先:插入,归并,快排都是需要全部都要排序结束才可以找出

则冒泡.简单选择,和堆排序可以用于这个前K个最大的元素

*冒泡 和简单选择都是 K n

堆排序:(4n) + k*log2n;空间复杂度:O(k),说是O(1)也行

package cn.itcast.domain;

import java.util.Arrays;
import cn.itcast.domain.*;
public class HeapdescSort {
    public static void main(String[] args) {
        int[]aa = new int[]{2,5,3,9,0,4,12};
        int[] leastNumbers = new HeapdescSort().getLeastNumbers(aa, 4);
        for (int i = 0; i < leastNumbers.length; i++) {
            System.out.println(leastNumbers[i]);
        }
        //System.out.println(leastNumbers.toString());

    }
    
    /**
    方法
    */
    


        public int[] getLeastNumbers(int[] arr, int k) {
            int []a = Arrays.copyOfRange(arr,0,k);
    

            buildHeap(a,a.length);
            /**
             * 找出前k个最小的元素,用大根堆的生成方法.
             * 先生成一个k个元素的大根堆.
             *  建立好大根堆之后,用给的表从k之后的元素与堆顶元素,比较,
             *  若小于堆顶,则用它替换堆顶,再进行大根堆的建立调整,(以便于找到下一个堆顶的元素与之比较)
             *             
             */
            for (int i = k; i <arr.length ; i++) {
                if (a[0] > arr[i]) {
                    a[0]  = arr[i];
                    adjustHeap(a,0,k);
                }

            }
            return a;

        }

        public void buildHeap(int[] arr, int length) {
            for (int i = length/2 -1; i >=0 ; i--) {
                adjustHeap(arr,i, length);

            }
        }

        public void adjustHeap(int[] arr, int k ,int length) {
            int temp = arr[k];
            for (int i = 2 * k + 1; i < length; i = 2 * i + 1) {
                if( i<length -1 && arr[i]<arr[i+1]){
                    i++;
                }
                if(temp >arr[i]){
                    break;
                }
                arr[k]= arr[i];
                k = i;
            }
            arr[k] =temp;


        }

}


归并排序和基数排序

  1. 归并排序

  2. 也是先简单递归划分一下,然后在归并

  3. 倒立的二叉树,如果是二路归并排序的话.

  4. 算法的精度在于最后的归并,

  5. 而快排的精度在于最先的划分思想

  6. 时间复杂度:

    • O(Log2n * n).与堆排序顺序不一样.遍历次数是树的高度为log2n.每次排序都要n个都要比较
  7. 空间复杂度:

    • .用的是递归的分治思想,递归的深度为log2n;,但是创建的数组的长度不定,最大是为N个元素的数组,每次都会逐次变大.则按照最大为O(N),则最大的空间复杂度是O(N)

归并的是两个相邻的有序子序列;

8归并的前提是:子序列是有序的组合,然后才能组合两个及其两个以上的子序列.

​ 怎么保证有序?递归到一个子序列中只有一个元素,自然就是有序的了,

此时,要求辅助数组B,每次复制的元素个数只能是两个有序子序列的元素之和:

9思路概括:

​ 核心:

​ 合并:将两个或者两个以上的有序组合合成一个新的有序表;主要在于merge()方法;

10代码写法:

  • 2先把所有的元素递归的排序;划分到最小的只有一个元素的时候;
  • 1在开始合并;
package cn.itcast.domain;

public class margeSort {
    public static void main(String[] args) {
        int[]aa = new int[]{2,5,3,9,0,4,12};

        new margeSort().margeSort(aa ,0,aa.length-1);
        for (int i = 0; i < aa.length; i++) {
            System.out.println(aa[i]);
        }
    }


    private void margeSort(int[] A, int low, int high) {
        if (low < high) {
            int mid= (low + high)/2;
            margeSort(A,low,mid);
            margeSort(A,mid +1,high);
            marge(A,low,mid,high);
        }
    }

    private void marge(int[] A, int low, int mid, int high) {
        int[] B = new int[A.length];
        /**
         * 注意:这里的k是<high,也就是说是B的数组的元素每次都是两个归并子序列的元素,不
         * 能全部复制过来,全部复制过来也就不是归并思想了
         *
         */
        
        //注意:这里是k<=high;最有一个是length()-1的下标值

        for (int k = 0; k < =high; k++) {
            B[k] = A[k];
        }
        /**
         * 在B数组中设立;两个指针,i和j,前后相互逐次比较,最小的放到A[i++]中;
         */
        int a = -1;
        int b = -1;
        int c = -1;
        for (int i = low, j = mid + 1, k = i; i <= mid && j <= high; k++) {
            if (B[i] < B[j]) {
                A[k] = B[i++];
            } else {
                A[k] = B[j++];
            }

            a = i;
            b = j;
            c = k;

        }
        //特别注意:这里是++c.不能写成c++了;

        A[++c] = (a<=mid)? B[a++]:B[b++];
       /* while(a <=mid){
            A[c++] = B[a++];
        }


        while(b<=high){
            A[c++] = B[b++];
        }
*/
    }


}

基数排序

思想:分配和收集

  • 时间复杂度:O(d(n+r))
  • 适合场景:n比较大,上亿也可以,r和d比较小,
  • r为最小单位,关键字
  • d是最小单位r的种类也是躺数,能分成几部分,
  • n为所有元素的遍历个数,也就是n个元素
  • 空间复杂度:O®;,r个辅助队列
  • 用三位数为例子:r为10,d为3趟,n为

搜索算法:

作者:城南亦南
链接:https://www.nowcoder.com/discuss/666534?source_id=discuss_experience_nctrack&channel=-1
来源:牛客网

算法了解哪些?

1、排序算法:快速排序、归并排序、计数排序
2、搜索算法:回溯、递归、剪枝
3、图论:最短路径、最小生成树、网络流建模
4、动态规划:背包问题、最长子序列、计数问题
5、基础技巧:分治、倍增、二分法、贪心算法

public class Solution {
    public int numWays(int n) {
        if (n == 0 || n == 1) {
            return 1;
        }
        int pre = 1, cur = 2;
        for (int i = 3; i <= n; i++) {
            int tmp = (pre + cur) % 1000_000_007;
            pre = cur;
            cur = tmp;
        }
        return cur;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值