函数封装第四式: 8种常见排序算法的实现整理 详细的注释助力你早日玩弄算法于股掌之间

文章目录

    • 概述
    • 算法
      • 冒泡排序(高效)
      • 快速排序
      • 直接插入排序
      • 希尔排序
      • 简单选择排序
      • 堆排序
      • 归并排序
      • 基数排序
    • 未完待续

概述

从排序分类一共分为4大项 8小项(像极了田径运动): 即插入排序直接插入、希尔排序),交换排序冒泡排序【高效实现】、快速排序````),**选择排序**(简单选择、堆排序),归并排序, 基数排序数组实现,队列实现),下面是算法的详细步骤 和详细注释


算法

冒泡排序(高效)

/**
  * 高效冒泡
  * 1.一共比较n-1轮
  *   每轮比较完后 设立一个是否交换的标志
  * 2.每次比较 n-轮数
  */
 public static void bubleSort(int[] arr) {
  for (int i = 1; i < arr.length; i++) {
   //true表示当前轮已经排好序 不需要交换
   boolean flag = true;
   for (int j = 0; j < arr.length - i; j++) {
    if (arr[j] > arr[j + 1]) {
     int temp = arr[j];
     arr[j] = arr[j + 1];
     arr[j + 1] = temp;
     //排好了
     flag = false;
    }
   }
   //如果到这还是true 说明已经排好序了
   if(flag)
    break;
   
  }
 }

快速排序

public static void main(String[] args) {
  int[] arr= new int[]{3, 1, 33,2, 38,6};
  quickSort(arr, 0, arr.length - 1);
  System.out.print(Arrays.toString(arr));
 }   
 
 
 /**
  * 要点: 每次划分两部分  前一部分比基准小  后一半都比基准大
  * @param arr
  * @param start
  * @param end
  */
 public static void quickSort(int[] arr, int start, int end) {
  //基线
  if (start < end) {
   //基准
   int stand = arr[start];
   //首指针
   int low = start;
   //尾指针
   int high = end;
   while(low < high) {
    //从后往前比较
    while(low < high && stand <= arr[high]) {
     high--;
    }
    //说明后边有更小的, 调整位置
    arr[low] = arr[high];
    //从前往后比较
    while(low < high && stand >= arr[low]) {
     low ++;
    }
    //前面部分的后边有更大的
    arr[high] = arr[low];
   }
   //归还基准 此时首尾重合
   arr[low] = stand;
   //对首尾两部分进行递归快排
   quickSort(arr, start, low);
   quickSort(arr, low + 1, end);
   
  }
  
  }

直接插入排序

/**
  * 从第一项开始  记录当前循环遍历的数 
  * 和前面部分进行比较 如果有比前面小的就交换到指定位置
  * @param arr
  */
 public static void insertSort(int[] arr) {
  for (int i = 1; i < arr.length; i++) {
   int temp = arr[i];
   int j;
   for (j = i-1; j >=0 && arr[j] > temp; j--) {
    //只要前面部分有比当前大的就往后挪  给插入当前留出位置  注意循环是往前的 仔细理解
    arr[j + 1] = arr[j];
   }
   //由于for退出 j还减了1 故指定位置还要往后移一个
   arr[j + 1] = temp;
  }
  }

希尔排序

/**
  * 核心就是划分步长
  * 开始步长取数组长度一半  然后每轮都是上一次的一半 直到步长 = 1
  * @param arr
  */
 public static void shellSort(int[] arr) {
  for (int d = arr.length / 2; d > 0; d /= 2) {
   //遍历划分步长的数组   从d开始刚好可以遍历所有部分
   for (int i = d; i < arr.length; i++) {
    //遍历每个划分后的数组的元素  进行一次冒泡排序  注:元素之间的间隔是d
    for (int j = i-d; j >= 0; j-=d) {
     if (arr[j] > arr[j + d]) {
      int temp = arr[j];
      arr[j] = arr[j + d];
      arr[j + d] = temp;
     }
    }
   }
  }
  }

简单选择排序

/**
  * 每次选择当前元素 为循环中最小的数 让后边元素依次和其比较
  * 如果有比它还小 进行交换 更新最小下标
  * @param arr
  */
 public static void easySelect(int[] arr) {
  
  for (int i = 0; i < arr.length; i++) {
   int min = i;
   for (int j = i + 1; j < arr.length; j++) {
    if (arr[j] < arr[min]) {
     min = j;
    }
   }
   if (min != i) {
    int temp = arr[i];
    arr[i] = arr[min];
    arr[min] = temp;
   }
  }
  }

堆排序

public static void main(String[] args) {
  int[] arr= new int[]{3, 1, 33,2, 38,6};
  //从最后一个节点的双亲节点 开始进行大顶堆调整 
  //获取这个双亲节点 也是根据性质
  int start = arr.length - 1 / 2;
  //从start 开始往前调整
  for (int i = start; i >= 0; i--) {
   maxTopHeap(arr, arr.length - 1, i);
  }
  //对调整好的大顶堆   从后往前  依次将第一个 和arr[i] 交换 
  for (int i = arr.length - 1; i >= 0; i-- ) {
   int temp = arr[0];
   arr[0] = arr[i];
   arr[i] = temp;
   //继续调整 这一次是从0开始调整
   maxTopHeap(arr, i, 0);
  }
  
  System.out.println(Arrays.toString(arr));
  
 }   
/**
  *  核心 将排序的数组 看成一个顺序二叉树 并调整成大顶堆
  *  大顶堆: 双亲节点大于左右子节点
  * @param count 还需要调整的次数  一开始就是 n-1
  * @param index 当前调整节点的下标
  */
 public static void maxTopHeap(int[] arr, int count, int index){
  //根据顺序二叉树的性质 得出当前节点的左右孩子节点
  int left = 2 * index  + 1;
  int right = 2 * index + 2;
  if (left < count && arr[left] > arr[index]) {
   int temp = arr[index];
   arr[index] = arr[left];
   arr[left] = temp;
   //可能调整完当前 破坏了之前的大顶堆 继续递归
   maxTopHeap(arr, count, left);
  }
  if (right < count && arr[right] > arr[index]) {
   int temp = arr[index];
   arr[index] = arr[right];
   arr[right] = temp;
   
   maxTopHeap(arr, count, right);
  }
  
  
  }

归并排序

public static void main(String[] args) {
  int[] arr= new int[]{3, 1, 33,2, 38,6};
  mergeSort(arr, 0, arr.length - 1);
  System.out.println(Arrays.toString(arr));
 }   
 
 
 public static void mergeSort(int[] arr, int start, int end) {
  //每次归并两部分
  if(start < end) {
   int mid = (start + end) /2;
   mergeSort(arr, start, mid);
   mergeSort(arr, mid + 1, end);
   merge(arr, start, mid, end);
  }
  
 }
/**
  * 归并: 每次只划分两部分 每次比较两个部分相同下标位置的元素 
  * 谁小放入临时数组中 ,最后合并作为下一次归并的基础
  * @param arr
  * @param start
  * @param end
  */
 public static void merge(int[] arr, int start, int mid, int end){
  //临时存储归并的元素
  int[] temp = new int[end - start + 1];
  int t = 0;
 
  int i = start;
  int j = mid +1;
  while(i <= mid && j <= end) {
   //如果前面部分对应下标更小
   if (arr[i] <= arr[j]) {
    temp[t ++] = arr[i];
    //继续从当前小的部分往后走
    i++;
   } else {
    temp[t++] = arr[j];
    //同上
    j++;
   }
    
   
  }
  //处理没有比较完的部分
  while (i <= mid) {
   temp[t++] = arr[i];
   i++;
  }
  while(j <= end) {
   temp[t++] = arr[j];
   j++;
  }
  
  //归还
  for (int k = 0; k < temp.length; k++) {
   arr[start + k] = temp[k];
  }
  
 }

基数排序


 /**
  * 基数排序的思想是: 每次 按位 将n个不同位数的依次放入 10个长度相同的数组中
  * 然后按顺序取出 循环往复 直到最大位数
  * @param arr
  */
 public static void redixSort(int[] arr){
  int max = Integer.MIN_VALUE;
  for (int i = 0; i < arr.length; i++) {
   if (max < arr[i]);
    max = arr[i];
  }
  //最大位数
  int n = String.valueOf(max).length();
  
  //临时存放按位取的数
  int[][] temp = new int[10][arr.length];
  //统计这个10个数组的数量
  int[] count = new int[10];
  //遍历所有位数 并依次取出
  for (int i = 0, k = 1; i < n; i++, k *= 10) {
   //遍历元素
   for (int j = 0; j < arr.length; j++) {
    //每一位的数
    int index = arr[j] / k % 10;
    temp[index][count[index]] = arr[j];
    count[index]++ ;
    
   }
  
   int l = 0;
   //依次取出 进行下一位遍历
   for (int m = 0; m < count.length; m++) {
    for (int j = 0; j < count[m]; j++) {
     arr[l++] = temp[m][j];
    }
    //为下一位的数组记录数量做准备
    count[m] = 0;
   }
   
   
  }

未完待续

今天放的都是满满干货, 这都是我今天自己一遍遍默认背下来 都是可以运行的, 历时2个小时写完8种排序 还是不熟悉 有点慢了, 今天就到这, 后面会逐步更新, 主要更新内容如下

  1. 每种算法时间复杂度分析
  2. 每种算法应用场景
    其他内容 敬请关注

觉得有帮助到你 请高抬贵手左上角谢谢, 也欢迎各位有问题进行留言.

你可能感兴趣的:(算法篇,数据结构)