数据结构---排序

目录

稳定性

插入排序 

直接插入排序

折半插入排序

希尔排序

选择排序

直接选择排序

冒泡排序

快速排序

堆排序

归并排序

 计数排序

基数排序

桶排序

总结


稳定性

排完序之后数据的相对顺序未发生改变,那么排序算法就具备稳定性

插入排序 

直接插入排序

时间复杂度:o(N^2),空间复杂度o(1),稳定的 

    public static void sort(int []arr){
        for (int i = 1; i < arr.length; i++) {
          for (int j=i;j>=1;j--){
              if(arr[j]<arr[j-1]){
                  int tmp=arr[j];
                  arr[j]=arr[j-1];
                  arr[j-1]=tmp;
              }else
                  break;
          }
        }
    }

折半插入排序

时间复杂度:o(N^2),空间复杂度o(1),稳定的 

 插入元素之前,元素有序,通过二分查找到插入位置

 public static void sort(int[] arr) {
    for (int i = 1; i < arr.length; i++) {
        if (arr[i] < arr[i - 1]) {
            //通过二分查找 找到插入位置
            int left = 0;
            int right = i - 1;
            while (left <= right) {
                int mid = (left + right) / 2;
                if (arr[mid] > arr[i]) {
                    right = mid - 1;
                } else
                    left = mid + 1;
            }
            int tmp = arr[i];
            for (int j = i; j > left; j--) {
                arr[j] = arr[j - 1];
            }
            arr[left] = tmp;
        }
    }
}

希尔排序

时间复杂度:和增量有关,约o(N^1.3-N^1.5)

空间复杂度o(1),非稳定的排序算法

直接插入排序在数据基本有序的情况下时间复杂度小小

希尔排序是对直接插入排序的优化,通过分组,使元素趋于有序

public  static void sort(int []arr,int d) {
        for (int j = d; j < arr.length; j++) {
            for (int k = j - d; k >= 0; k -= d) {
                if (arr[k] > arr[k + d]) {
                    int tmp = arr[k];
                    arr[k] = arr[k + d];
                    arr[k + d] = tmp;
                }
            }
        }
    }

public static void shell(int []array) {
//设计步长
    int i=array.length/2;
    while(i>1) {
        sort(array, i);
        i/=2;
    }
//最后进行直接插入排序
    sort(array,1);
}

选择排序

直接选择排序

时间复杂度:o(N^2),空间复杂度o(1),不稳定的 

    public static void sort(int []arr){
        for (int i = 0; i <arr.length ; i++) {
            for (int j = i+1; j < arr.length; j++) {
                if(arr[j]<arr[i]){
                    int tmp=arr[j];
                    arr[j]=arr[i];
                    arr[i]=tmp;
                }
            }
        }
    }

冒泡排序

时间复杂度:o(N^2),空间复杂度o(1),稳定的 

每一选择最大或者最小的元素放到最后

(最后一趟,元素已经有序了 N个元素,走N-1趟)

    public static void sort(int []arr) {
        for (int i = 0; i < arr.length-1 ; i++) {
            int flag=0;
            for (int j = 0; j < arr.length-1-i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                    flag=1;
                }
            }
            if(flag==0)
                break;
        }
    }

快速排序

  1. 从数列中挑出一个元素作为基准。
  2. 重新排列数列,把所有的比基准小的放在基准前面,反之放在后面(一样大可任意一边)完成后基准处在分区的中间位置。
  3. 通过递归调用把小于基准元素和大雨基准元素的子序列进行排序

时间复杂度 最好:O(N*log2 N)最坏(数据有序)o(N^2)

空间复杂度O(log2N) 最坏o(N)

不稳定的排序

public static void sort(int []arr){
    quicksort(arr,0,arr.length-1);
}
public static void quicksort(int []arr,int start,int end){
    if(start>end)
        return;
   int index= position(arr,start,end);
   quicksort(arr,start,index-1);//左边
    quicksort(arr,index+1,end);//右边
}
public static int position(int []arr,int start,int end){
int tmp=arr[start];
while(start<end){
    while(start<end&&arr[end]>=tmp){
        end--;
    }
    //arr[end]找到了<tmp的值
    arr[start]=arr[end];
    while(start<end&&arr[start]<=tmp){
        start++;
    }
    //arr[start]找到了>tmp的值
    arr[end]=arr[start];
}
//start和end相遇了
    arr[start]=tmp;
return start;
}

 对于快排的优化:元素有序且数据过多时,递归深度太深,栈溢出

 三数取中法:

arr【left】,arr【right】,arr【mid】找到中间值的下标

 public static void sort(int[] arr) {
        quicksort(arr, 0, arr.length - 1);
    }
    public static int find(int []arr,int start,int end) {
        int mid = (start + end) /2;
        if(arr[start]<arr[end]){//3 ? 8
            if(arr[mid]>arr[end])//3 10 8
                return  end;
            else if(arr[start]<arr[mid])//3 6 8
                return mid;
            else//3 1 8
                return start;
        }
        else{//8  ? 3
            if(arr[mid]>arr[start])//  8  10 3
                return start;
            else if(arr[mid]<arr[end])//  8 1  3
                return  end;
            else //8 5 3
                return mid;
        }
    }
    public static void quicksort(int []arr,int start,int end) {
        if (end < start)
            return;
      //  找基准之前,知道中间值下标
        int index = find(arr, start, end);
        int tmp = arr[start];
        arr[start] = arr[index];
        arr[index] = tmp;
        int x = position(arr, start, end);
        quicksort(arr, x + 1, end);
        quicksort(arr, start, x - 1);
    }
    public static int position(int []arr,int start,int end) {
        int x = arr[start];
        while (start < end) {
            while (end > start && arr[end] >= x)
                end--;
            arr[start] = arr[end];
            while (end > start && arr[start] <= x)
                start++;
            arr[end] = arr[start];
        }
        arr[start] = x;
        return start;
    }
    public static void main(String[] args) {
        int []array =new int[100000];
        for (int i = 0; i <100000 ; i++) {
            array[i]=i;
        }
        sort(array);
        for (int j : array) {
            System.out.print(j + " ");
        }
    }
}

 快排的非递归实现

    public  static void sortStack(int []arr,int start,int end){
        Stack<Integer>stack=new Stack<>();
        stack.push(end);
       stack.push(start);
       while(!stack.isEmpty()) {
           int left = stack.pop();
           int right = stack.pop();
           int pivor = position(arr, left, right);
           if (pivor - left > 1) {//左区间有两个以上的元素
               stack.push(pivor - 1);
               stack.push(left);
           }
           if (right - pivor > 1) {//右区间有两个以上的元素
               stack.push(end);
               stack.push(pivor + 1);
           }
       }
    }

堆排序

时间复杂度:o(N^log2 N),空间复杂度o(1),不稳定

public  static void sort(int []arr){
        creat(arr);
        int end=arr.length-1;
        int sz=arr.length;
        while (end>=0){
            int tmp=arr[end];
            arr[end]=arr[0];
            arr[0]=tmp;
            shifdown(arr,0,end);
            end--;
        }
    }
    public static void  shifdown(int []arr,int parent,int sz) {
        int left = parent * 2 + 1;
        while (left <sz) {
            if (left + 1 <sz) {
                if (arr[left + 1] > arr[left])
                    left++;
            }
            if (arr[parent] < arr[left]) {
                int tmp = arr[parent];
                arr[parent] = arr[left];
                arr[left] = tmp;
                parent = left;
                left = parent * 2 + 1;
            }else
                break;
        }
    }
    public static void creat(int []arr){//创建大根堆
        for (int parent =(arr.length-2)/2 ; parent >=0 ; parent--) {
            shifdown(arr,parent,arr.length);
        }
    }

归并排序

时间复杂度:o(N^log2 N),空间复杂度o(N),稳定

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

基础:实现两个有序数组合并

    public static int [] add(int []nums1,int []nums2){
        int []arr=new int[nums1.length+nums2.length];
        int i=0;int j=0,k=0;
        //nums1[1,2,3] nums2[2,3]
        while(i<nums1.length&&j< nums2.length){
            if(nums1[i]<nums2[j]){
                arr[k++]=nums1[i++];
            }else
                arr[k++]=nums2[j++];
        }
        while(j<nums2.length){
            arr[k++]=nums2[j++];
        }
        while(i<nums1.length){
            arr[k++]=nums1[i++];
        }
        return arr;
    }

  //0 1 2 3  [start,end]
    public static void mergeadd(int[] arr, int start, int mid, int end) {
        int[] array = new int[end - start + 1];
        int i = start;
        int j = mid + 1, k = 0;
        //nums1[1,2,3] nums2[2,3]
        while (i <= mid && j <= end) {
            if (arr[i] < arr[j]) {
                array[k++] = arr[i++];
            } else
                array[k++] = arr[j++];
        }
        while (j <= end) {
            array[k++] = arr[j++];
        }
        while (i <= mid) {
            array[k++] = arr[i++];
        }
        //开始位置时start,每次是0导致覆盖
        System.arraycopy(array, 0, arr, start, array.length);
    }

    public static void merge(int[] arr, int start, int end) {
        if (start >= end)
            return;
        int mid = (start + end) / 2;//1 0
        //左
        merge(arr, start, mid);//0 1 0 0
        //右
        merge(arr, mid + 1, end);
        //合并
        mergeadd(arr, start, mid, end);
    }

    public static void mergeSort(int[] arr) {
        merge(arr, 0, arr.length - 1);
    }
 public static void main(String[] args) {
        int[] nums1 = {1, 8, 3, 7, 5, 9, 6, 0};
        mergeSort(nums1);
        System.out.println(Arrays.toString(nums1));
    }

非递归实现:按照递归的思想,每组元素个数减半,直到每个数组元素都只有一个之后,开始数组元素*2合并

    public static void usualmerge(int[] arr) {
        int gps=1;
        while(gps<arr.length){
            for (int i = 0; i < arr.length; i+=gps*2) {
                int start=i;
                int mid=i+gps-1;
                if(mid>arr.length-1)//
                 mid=arr.length-1;
               int end =i+2*gps-1;
                if(end>arr.length-1)//
                    end=arr.length-1;
                mergeadd(arr,start,mid,end);
            }
            gps*=2;
        }
    }

 计数排序

时间复杂度O(N),空间复杂度O(M) 本质上稳定

    public static void countSort(int[] arr) {
        int max = arr[0], min = max;
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max)
                max = arr[i];
            if (arr[i] < min)
                min = arr[i];
        }
        //610 min=600 nums[10]=1
        int[] nums = new int[max - min + 1];

        for (int i = 0; i < arr.length; i++) {
            nums[arr[i] - min]++;
        }
        int j = 0;
        for (int i = 0; i < nums.length; i++) {
            for (int k = 0; k < nums[i]; k++) {
                arr[j] = i + min;
                j++;
            }
        }
    }

基数排序

//最高位为D,那么执行D次//排序数组有N个元素//收集桶中的元素到数组中

时间复杂度:给定N个D位数(取值范围为R),基数排序需要比较元素的每一位,则复杂度为O(D(N+R)),其中一轮循环分配时间复杂度为O(N),一轮循环收集时间复杂度为O(R),共需要d次循环来进行分配收集

时间复杂度:O(D(N+R)),空间复杂度O(N*R),稳定

 //基数排序
    public  static int getLength(int []arr,int mod){
        int max=0;
        for (int j:arr) {
            int s=0;
           while(j!=0){
               j/=mod;
               s++;
           }
           max=Math.max(s,max);
        }
        return max;
    }
    public static void copy(int [][]count,int []arr,int mod){
        int k=0;
        for (int i = 0; i <mod*2 ; i++) {
            for (int j = 0; j <count[i].length ; j++) {
                arr[k++]=count[i][j];
            }
        }
    }
    public static void creat(int [][]count,int index,int value ) {
        count[index] = Arrays.copyOf(count[index], count[index].length + 1);
        count[index][count[index].length-1]=value;
    }
    public  static void  sort(int []arr){
        int mod=10;
        //如果有负数,一共mod*2
        int [][]count=new int[mod*2][0];
      int length=getLength(arr,mod);
      int div=1;
        for (int i = 0; i < length; i++) {//最高有几位数,就要执行几趟
            for (int j = 0; j < arr.length; j++) {
                int num = arr[j];
                num /= div;
                int index = (num % mod)+mod-1;//如果有负数 [0,9],[10,19]
                // 两位数12 /100=0,
                creat(count, index, arr[j]);
            }
            div*=10;
            //每一次读完了,数组被重新赋值
            copy(count,arr,mod);
            //count也全部置空
            count=new int[mod*2][0];
        }
    }

桶排序

时间复杂度:根据调用排序的方法而不同

桶排序:每个桶存储一定范围的数值,分别对桶内元素排序

public static void Sort(int []arr){
        int mod=4;
        //4个桶,装-100~100的数字
        int [][]count=new int [mod][0];
    for (int i = 0; i < arr.length; i++) {
        if(arr[i]<-50){
            set(count,0,arr[i]);
        }else if(arr[i]>=-50&&arr[i]<0) {
            set(count, 1, arr[i]);
        } else if(arr[i]>=0&&arr[i]<50) {
            set(count, 2, arr[i]);
        } else
            set(count,3,arr[i]);
    }
    int j=0;
    for (int i = 0; i <mod ; i++) {
        quicksort(count[i],0,count[i].length-1);
        System.arraycopy(count[i],0,arr,j,count[i].length);
        j+=count[i].length;
    }
}

总结

外部排序:内存只有1G,需要排序的元素有10G,那么需要借助磁盘等外部设备存储排序

(数据分为多个文件,使每个文件内的元素有序,使用归并排序将所有文件归并为大文件)

排序的总结

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值