八种排序算法

395 阅读2分钟

假设数组的大小为n,数组为整数数组。

1.选择排序

每次排序从下标i开始,然后逐个比较i+1到n的元素,保证i位置上的元素是[i,n-1]中最小的(倒序为最大)。

在进行比较过程中,根据排序的标准,如果为正序,则将较小的保留在前面,较大的保留在后面。

public void ChooseSort(int[] nums){
  for(int i = 0;i<nums.length;i++){
      for(int j = i+1;j<n;j++){
          if(nums[i]>nums[j]){
              int temp = nums[i];
              nums[i] = nums[j];
              nums[j] = temp;
          }
      }
  }
}

2.冒泡排序

两两依次比较,较大的放在后面。 每一轮比较之后,最后一位就是最大的值,从而使得下一轮可以少比较一位数字。

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

其实冒泡和选择排序很像,只是选择排序对比的过程中前一个数始终是不变的,也就是要确定的目前最小值的下标,逐步将最小值换到当前位置。而冒泡排序是确定最大值,不断地两两向后对比,将较大值换到后面,然后最终确认当前范围的最大值。

3.快速排序

以数组的第一个数为基数,从后往前找,比它小的数,覆盖基数的位置。再从前往后找比它大的数,再覆盖到刚才比他小的数的位置。逐次寻找直到前后位置重合,此时这个位置就基数最后应该放入的位置,它对应于上一次比基数大的位置或者比基数小的位置。

public void quickSort(int[] nums,int start,int end){
    if(start<end){
       int low = start;
       int high = end;
       int std = nums[low];
       while(low<high){
          while(low<high&&nums[high]>=std){
              high--;
          }
          //用右边的数替换左边的数
          nums[low] = nums[high];
          while(low<high&&nums[low]<=std){
              low++;
          }
          //用左边的数代替右边的数
          nums[high] = nums[low];
       }
       //此时 low=high,将std填入
       nums[low] = std;
       //处理标准数左边的数组
       quickSort(nums,start,low-1);
       //处理标准数右边的数组
       quickSort(nums,low+1,end);
    }
}

4.插入排序

认为前n个数是有序的,当插入第n+1个数的时候,从右往左依次对比,若小于则和前一个数进行互换,类似于冒泡。

public void insertSort(int[] nums){
    for(int i = 0;i<nums.length;i++){
        for(int j = i;j>0;j--){
            if(nums[j]<nums[j-1]){
                int temp = nums[j];
                nums[j] = nums[j-1];
                nums[j-1] = temp;
            }
        }
    }
}

5.希尔排序

基于插入排序的思想,首先将数组按步长分成不同的部分,然后每个部分进行插入排序

public void shellSort(int[] nums){
    for(int d = nums.length/2;d>0;d/=2){
        for(int i = 0;i<d;i++){ 
            //这一部分是插入排序
            for(int j = i;j<nums.length;j+=d){
                for(int k = j;k>i;k-=d){
                    if(nums[k]<nums[k-d]){
                        int temp = nums[k];
                        nums[k] = nums[k-d];
                        nums[k-d] = temp;
                    }
                }
            }
        }
    }
}

6.归并排序

将数组分成两个部分,然后依次递归,直到变成一个数字为止。而对于一个数字来说,他是有序的,再反向不断归并,成为一个有序的数组。

//1.首先假设已经把数组分成了两个有序部分,并对有序的部分进行合并
public void merge(int[] nums, int low,int mid,int high){
    //用i,j两个变量分别来索引前半部分和后半部分的有序数字集合
    int i = low;
    int j = mid+1;
    //用于存储归并后的有序的临时数组
    int[] temp = new int[high-low+1];
    int index = 0;
    while(i<=mid&&j<=high){
        if(nums[i]<nums[j]){
            temp[index] = nums[i];
            i++;
        }else{
            temp[index] = nums[j];
            j++;
        }
        index ++;
    }
    while(i<=mid){
        temp[index]=nums[i];
        i++;
        index++;
    }
    while(j<=high){
        temp[index]=nums[j];
        j++;
        index++;
    }
    //最后把临时数组填入原数组的对应位置
    for(int k=0;k<high-low+1;k++){
       nums[low+k] = temp[k];
    }
}

//2.然后写递归部分
public void mergeSort(int[] nums, int low, int high){
     int mid = (low+high)/2;
     if(low<high){
         //先不断二分
         mergeSort(nums,low,mid);
         mergeSort(nums,mid+1,high);
         //再自底向上不断归并
         merge(nums,low,mid,high);
     }
}

7.基数排序

基数排序就是从数字的每一位出发,先按当前位进行总体上的排序,然后不断将位数提高,修正排序结果

public void radixSort(int[] nums){
    int n = nums.length;
    //找到所有数字中的最大值,最大值具有的位数是最长的
    int max = Integer.MIN_VALE;
    for(int i = 0;i<n;i++){
       max = Math.max(max,nums[i]);
    }
    int max_length = (max+"").length();
    //建立用来存储当前位数字是i的temp[i][n]数组
    int[][] temp = new int[10][n];
    //建立计算当前位是i的数字有多少个的数组
    int[][] temp_count = new int[10];
    //对每一位循环进行排序
    for(int i = 0;i<max_length;i++){
        for(int j = 0;j<n;j++){
            int num = nums[j];
            //计算所有数组元素当前位的数字
            int y = (num/Math.pow(10,i))%10;
            temp[y][temp_count[y]] = num;
            temp_count[y]++;
        }
        //依次从最低位到最高位填入原数组
        int index = 0;
        for(int k = 0;k<10;k++){
            if(temp_count[k]!=0){
               for(int l = 0;l<temp_count[k];l++){
                   nums[index] = temp[k][l];
                   index++;
               }
            }
            temp_count[k] = 0;
        }
    }
}

8.堆排序

//1.首先要实现最大堆,将数组形成最大堆
public void maxheap(int[] nums, int size, int index){
    //左子节点和右子节点
    int left = 2*index+1;
    int right = 2*index+2;
    //找到两个节点中的最大值
    int max = index;
    if(left<size&&nums[left]>nums[max]){
        max = left;
    }
    if(right<size&&nums[right]>nums[max]){
        max = right;  
    }
    
    //交换位置
    if(max!=index){
       int temp = nums[max];
       nums[max] = nums[index];
       nums[index] = temp;
       //交换位置后继续后面的堆
       maxheap(nums,size,max);
    } 
}
//2.大顶堆实现从小到大排序
public void heapSort(int[] nums){
    int n = nums.length; 
    //首先建立原数组的大顶堆
    //开始位置是最后一个非叶子节点,也是最后一个节点的父节点
    int start = (n-1)/2;
    for(int i = start;i>=0;i--){
        maxheap(nums,n,i);
    }
    //此时数组已经变成了大顶堆,即父节点要大于子节点
    for(int i = n-1;i>=0;i++){
       //接下来,每次将堆顶的元素换到后面第i个位置,然后再对前0~i-1的位置进行最大堆调整
       int temp = nums[0];
       nums[0] = nums[i];
       nums[i] = temp;
       //对前0~i-1的位置进行最大堆调整
       //除了堆顶根节点以及其左右子树不是大顶堆,其他都是,所以从堆顶开始调整
       maxheap(nums,i,0);
    }
}