Performance and implementation of various sorting

Java sorting methods are divided into comparison-based sorting methods and non-comparison-based sorting methods. The comparison-based sorting method is suitable for data of all sizes and has a wide range of applications. Non-comparison-based sorting methods require space to determine their unique position, so their applicability is limited.

If stability is not required, the data size is small, and the data is disordered, choose quick sort; if stability is required, the data size is small, and the data is in order, insert sorting is required; if the data is disordered, choose merge sort; if If the data size is large, choose quick sort, merge sort, or heap sort.

1. Sorting method based on comparison

1. Bubble sort

Stability: stable

Time complexity: O(N) --O(N^2) 

Space complexity: O(1)

Principle: Repeatedly access a set of arrays, compare two adjacent elements each time, and then exchange them according to size.

 public static void bubbleSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            boolean flag = false;
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j] > array[j + 1]) {
                    swap(array, j, j + 1);
                    flag = true;
                }
            }
            if (!flag) {
                break;
            }
        }
    }

2. Insertion sort

Stability: stable

Time complexity: O(N) --O(N^2) When the data is relatively ordered, insertion sort is more efficient.

Space complexity: O(1)

Principle: Treat the first element in a set of arrays as an ordered array, treat the second element to the last element as an unsorted array, scan, and insert forward in order, similar to drawing playing cards.

public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int tmp = array[i];//记录要插入的数据
            for (int j = i-1; j >= 0; j--) {//从最右边开始找比其小的数
                if(array[j] > tmp) {
                    array[j+1] = array[j];
                }else{
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

3. Hill sorting

Stability: Unstable

Time complexity: O(N)--O(N^2)

Space complexity: O(1)

Principle: Hill sorting is a more efficient sorting method than insertion sort, but it is unstable. Hill sorting first divides the entire sequence to be sorted into several subsequences, and then performs insertion sorting respectively. When the entire sequence is basically in order, all elements are then inserted and sorted in sequence.

 public static void shellSort(int[] array){
       int gap= array.length;
       while(gap>1){
           gap/=2;
           shell(array,gap);
       }
   }
   private static void shell(int[] array, int gap){
       for(int i=gap;i< array.length;i++){
           int tmp=array[i];
           int j=i-gap;
           for(;j>=0;j-=gap){
               if(array[j]>tmp){
                   array[j+gap]=array[j];
               }else{
                   break;
               }
           }
           array[i+gap]=tmp;
       }
   }

4. Merge sort

Stability: stable

Time complexity: O(n * log(n))

Space complexity: O(n) takes up auxiliary space

Principle: Merge sort is an algorithmic application of the divide-and-conquer method. Two pointers are set, and the starting positions are at the first of the two sorted sequences. The elements pointed to by the two pointers are compared, and the relatively small elements are put into Merge the space and move the pointer to the next position.

 public static void mergeSort(int[] array){
        int gap=1;
        while(gap<array.length){
            for(int i=0;i<array.length;i+=gap*2){
                int left=i;
                int mid=left+gap;
                int right=mid+gap;
                if(mid>=array.length){
                    mid= array.length;
                }
                if(right>= array.length){
                    right= array.length;
                }
                merge(array,left,mid,right);
            }
           gap*=2;
        }
    }
    private static void merge(int[] array, int left, int mid, int right){
        int s1=left;
        int e1=mid;
        int s2=mid+1;
        int e2=right;
        int[] tmp=new int[right-left+1];
        int k=0;//tmp数组的下标
        while(s1<=e1 && s2<=e2){
            if(array[s1]<=array[s2]){
                tmp[k++]=array[s1++];
            }else{
                tmp[k++]=array[s2++];
            }
        }
        while(s1<=e1){
            tmp[k++]=array[s1++];
        }
        while(s2<=e2){
            tmp[k++]=array[s2++];
        }
        for(int i=0;i<k;i++){
            array[i+left]=tmp[i];
        }
    }

5. Heap sort

Stability: Unstable

Time complexity: O(n * log(n))

Space complexity: O(1)

Principle: A stack is a structure similar to a complete binary tree, where the index of a child node is always less than or greater than its parent node. Create a large root heap for ascending sorting and a small root heap for descending sorting.

  public static void heapSort(int[] array){
      createBigHeap(array);//创建大根堆
      int end= array.length-1;
      while(end>0){
          swap(array,end,0);//交换堆首和堆尾
          shiftDown(array,0,end);//把新的数组顶端数据调整到相应位置
          end--;
      }
  }
  private static void createBigHeap(int[] array){
      for(int i=(array.length-1-1)/2;i>=0;i--){
          shiftDown(array,i,array.length);
      }
  }
  private static void shiftDown(int[] array, int parent, int len){
      int child=parent*2+1;
      while(child<len){
          if(child+1<len && array[child]<array[child+1]){
              child++;
          }
          if(array[child]>array[parent]){
              swap(array, child, parent);
              parent=child;
              child=parent*2+1;
          }else{
              break;
          }
      }
  }

6. Select sort

Stability: Unstable

Time complexity: O(n^2)

Space complexity: O(1)

Principle: Find the smallest or largest element in the unsorted array, put it at the beginning of the sequence, then continue to find the smallest or largest element from the remaining unsorted array, and put it at the end of the sorted sequence.

public static void selectSort(int[] array){
    for(int i=0;i< array.length;i++){
        int minIndex=i;
        for(int j=i+1;j< array.length;j++){
            if(array[j]<array[minIndex]){
                minIndex=j;
            }
        }
        swap(array,minIndex,i);
    }
}

7. Quick sort

Stability: Unstable

Time complexity: O(n * log(n))--O(n^2)

Space complexity: O(log(n)) ~ O(n)

Principle: Quick sort is much more efficient than other sorting methods. It uses the divide-and-conquer method to divide a sequence into two sub-series. There are 3 versions of quick sort. The basic idea is to first pick an element from the array as a benchmark, compare the remaining elements with their base values, and divide them into two areas, with the smaller one on one side and the larger one on the other side. The base value is now in the middle and then sorted recursively.

//Hoare法
    private static int partition(int[] array, int left, int right){
        int i=left;//记录这个位置
        int tmp=array[left];
        while(left<right){
            while(left<right && array[right]>=tmp){
                right--;
            }
            while(left<right && array[left]<=tmp){
                left++;
            }
            swap(array,left,right);
        }
        swap(array,left,i);
        return left;
    }

    //挖坑法
    private int partition(int[] array, int left, int right){
        int tmp=array[left];
        while(left<right){
            while(left<right && array[right]>=tmp){
                right--;
            }
            array[left]=array[right];
            while(left<right && array[left]<=tmp){
                left++;
            }
            array[right]=array[left];
        }
        array[left]=tmp;
        return left;
    }

    //前后指针法
    private static void partition(int[] array, int left, int right){
        int prev=left;
        int cur=left+1;
        while(cur<=right){
            if(array[cur]<array[left] && array[++prev]!=array[cur]){
                swap(array,cur,prev);
            }
            cur++;
        }
        swap(array, prev, left);
        return prev;
    }

2. Sorting methods not based on comparison-counting sort vs bucket sort

1. Counting sort

Stability: Stable
Time complexity: O(MAX(N, range))
Space complexity: O(range)

Principle: Counting sorting is very efficient when the data range is concentrated, but its applicable scope and scenarios are limited. Counting sort, also known as the pigeonhole principle, is a modified application of the hash direct addressing method. Count the number of occurrences of the same elements, and assign the sequence to the original sequence based on the statistical results.

 public static void countArray(int[] array){
      int max=array[0]; //找到数组当中的最大值和最小值
      int min=array[0];
      for(int i=1;i< array.length;i++){
          if(array[i]<min){
              min=array[i];
          }
          if(array[i]>max){
              max=array[i];
          }
      }
      int range=max-min+1; //确定计数数组的大小
      int[] count=new int[range];
      //遍历原来的数组 把原来的数据 和 计数数组的下标进行对应,来计数
      for(int i=0;i< array.length;i++){
          int val=array[i];
          count[val-min]++;
      }
      //遍历计数数组 
      int index=0;
      for(int i=0;i<count.length;i++){ 
          int val=count[i];
          while(val!=0){
              array[index]=i+min;
              val--;
              index++;
          }
      }
  }

2. Bucket sorting

Stability: stable

Time complexity: O(N)

Space complexity: O(n+k)

Principle: Bucket sorting is an extended version of counting sorting. Bucket sorting is based on the element size. Each bucket stores a certain range of elements, and the elements in the bucket are assigned to the original array according to the order of the buckets.

public static void bucketSort(int[] array){
      int max=array[0]; //找到数组当中的最大值和最小值
      int min=array[0];
      for(int i=1;i< array.length;i++){
          if(array[i]<min){
              min=array[i];
          }
          if(array[i]>max){
              max=array[i];
          }
      }
      int range=(max-min)/ array.length+1; //确定桶的数量
      ArrayList<ArrayList<Integer>> bucket=new ArrayList<>(range);
      for(int i=0;i< array.length;i++){
        bucket.add(new ArrayList<Integer>());
      }
      //将每个元素放入桶
      for(int i=0;i< array.length;i++){
          int num=(array[i]-min)/(array.length);
          bucket.get(num).add(array[i]);
      }
      //对每个桶进行排序
      for(int i=0;i<bucket.size();i++){
          Collections.sort(bucket.get(i));
      }
      //将桶中的元素赋值到原数组中
      int index=0;
      for(int i=0;i<bucket.size();i++){
         for(int j=0;j<bucket.get(i).size();j++){
             array[index++]=bucket.get(i).get(j);
          }
      }
  }

Guess you like

Origin blog.csdn.net/m0_72000264/article/details/130621303