排序算法总结

package cn.hucn;

/**
 * 排序算法的整理
 *
 * @author HuaHua
 * @v2017-11-9@上午10:04:47
 * @Sortfunction.java
 */

public class Sortfunction {

 /**
  * @param args
  */
 public static void main(String[] args) {
  int arr[] = { 1, 45, 78, 43, 23, 99, 66, 4 };
  // int res[]=bubleSort(arr);//冒泡
  // int res[]=bubleSort2(arr);//冒泡优化
  // int res[]=jiweiSort(arr);//鸡尾酒排序

  // int res[]=selectSort(arr);//选择
  // int res[]=selectSort2(arr);//选择2

  // int res[]=insertSort(arr);//插入排序
  // int res[] = binaryInsertSort(arr);// 二分插入排序

  // int res[] = shellSort(arr);// 希尔排序

  // int res[] = mergeSort(arr, 0, arr.length - 1);// 归并排序

  // int res[] = quickSort(arr, 0, arr.length - 1);// 快速排序

  int res[] = heapSort(arr);// 堆排序
  for (int i : res) {
   System.out.println(i);
  }

 }

 /**
  * 堆排序
  * // 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ----
  * O(nlogn) // 最优时间复杂度 ---- O(nlogn) // 平均时间复杂度 ---- O(nlogn) // 所需辅助空------ O(1) // 稳定性 ------------ 不稳定
  *
  * @param arr
  * @return
  */
 private static int[] heapSort(int[] arr) {
  int heap_size = buildHeap(arr);
  while (heap_size > 1) { // 堆(无序区)元素个数大于1,未完成排序
   // 将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素
   // 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
   swap(arr, 0, --heap_size);
   heapify(arr, 0, heap_size);// 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)
  }
  return arr;
 }

 private static int buildHeap(int[] arr) {// 建堆,时间复杂度O(n)
  int heap_size = arr.length;
  for (int i = heap_size / 2 - 1; i >= 0; i--) {// 从每一个非叶结点开始向下进行堆调整
   heapify(arr, i, heap_size);
  }
  return heap_size;
 }

 private static void heapify(int[] arr, int i, int heap_size) {// 从A[i]向下进行堆调整
  int left_child = 2 * i + 1;// 当前节点的左孩子索引
  int right_child = 2 * i + 2;
  int max = i;
  // 当前结点与其左孩子、右孩子比较,记住最大值的索引
  if (left_child < heap_size && arr[left_child] > arr[max]) {
   max = left_child;
  }
  if (right_child < heap_size && arr[right_child] > arr[max]) {
   max = right_child;
  }
  if (max != i) {
   swap(arr, max, i);
   heapify(arr, max, heap_size);
  }
 }

 /**
  * 快速排序 分类 ------------ 内部比较排序 // 数据结构 --------- 数组 // 最差时间复杂度 ----
  * 每次选取的基准都是最大(或最小)的元素,导致每次只划分出了一个分区,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2) //
  * 最优时间复杂度 ---- 每次选取的基准都是中位数,这样每次都均匀的划分出两个分区,只需要logn次划分就能结束递归,时间复杂度为O(nlogn)
  * // 平均时间复杂度 ---- O(nlogn) // 所需辅助空间 ------
  * 主要是递归造成的栈空间的使用(用来保存left和right等局部变量),取决于递归树的深度,一般为O(logn),最差为O(n) // 稳定性
  * --------- - 不稳定
  *
  * @param arr
  * @param left
  * @param right
  * @return
  */
 private static int[] quickSort(int[] arr, int left, int right) {
  if (left < right) {
   int q = partition(arr, left, right);// 划分函数
   quickSort(arr, left, q - 1);
   quickSort(arr, q + 1, right);
  }
  return arr;
 }

 private static int partition(int[] arr, int left, int right) {
  int jz = arr[right];// 每一次都选最后一个元素最为基准
  int tail = left - 1;// tail为小于基准的子序列的最后一个索引
  for (int i = left; i < right; i++) {
   if (arr[i] < jz) {
    swap(arr, ++tail, i);
   }
  }
  swap(arr, tail + 1, right);
  return tail + 1;
 }

 /**
  * 归并排序 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ----
  * O(nlogn) // 最优时间复杂度 ---- O(nlogn) // 平均时间复杂度 ---- O(nlogn) // 所需辅助空间
  * ------ O(n) // 稳定性 ------------ 稳定
  *
  * @param arr
  * @param left
  * @param right
  * @return
  */
 private static int[] mergeSort(int[] arr, int left, int right) {
  if (left < right) {
   int mid = (left + right) / 2;
   mergeSort(arr, left, mid);
   mergeSort(arr, mid + 1, right);
   merge(arr, left, mid, right);
  }
  return arr;
 }

 private static void merge(int[] arr, int left, int mid, int right) {
  int len = right - left + 1;
  int temp[] = new int[len]; // 辅助空间O(n)
  int index = 0;
  int i = left; // 前一数组的起始元素
  int j = mid + 1; // 后一数组的起始元素
  while (i <= mid && j <= right) {// 持续到一个子序列排完为止
   temp[index++] = arr[i] <= arr[j] ? arr[i++] : arr[j++]; // 带等号保证归并排序的稳定性
  }
  while (i <= mid) {// 右边排完
   temp[index++] = arr[i++];
  }
  while (j <= right) {// 左边排序完毕
   temp[index++] = arr[j++];
  }
  for (int k = 0; k < len; k++) {// 把结果复制到原来的数组
   arr[left++] = temp[k];
  }

 }

 /**
  *
  * 希尔排序
  *
  * // 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ----
  * 根据步长序列的不同而不同。已知最好的为O(n(logn)^2) // 最优时间复杂度 ---- O(n) // 平均时间复杂度 ----
  * 根据步长序列的不同而不同。 // 所需辅助空间 ------ O(1) // 稳定性 ------------ 不稳定
  *
  * @param arr
  * @return
  */
 private static int[] shellSort(int[] arr) {
  for (int gap = (arr.length + 1) / 2; gap > 0; gap /= 2) {// 进行分组,初始值为(n+1)/2,然后依次减半,最后等于一
   // 进行组内插入排序
   for (int i = 1; i < arr.length - gap + 1; i++) {
    int temp = arr[i];// 待插入的数
    int j = i - 1;// 从第j个位置比较
    while (j >= 0 && arr[j] > temp) {
     arr[j + 1] = arr[j];
     j--;
    }
    arr[j + 1] = temp;
   }
  }
  return arr;
 }

 /**
  * 二分插入排序 前提:数列有序 // 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组
  * //最差时间复杂度 ---- O(n^2) // 最优时间复杂度 ---- O(nlogn) // 平均时间复杂度 ---- O(n^2)
  * //所需辅助空间 ------ O(1) // 稳定性 ------------ 稳定
  *
  * @param arr
  * @return
  */
 private static int[] binaryInsertSort(int[] arr) {
  for (int i = 1; i < arr.length; i++) {// 趟数
   int temp = arr[i];// 待插入的数
   int low = 0;
   int high = i - 1;
   int mid;
   while (low <= high) {
    mid = (low + high) / 2;
    if (arr[mid] > temp) {// 右边的都比temp大
     high = mid - 1;
    } else {// 右边的都>=temp
     low = mid + 1;
    }
   }
   for (int j = i - 1; j >= low; j--) {// // 将欲插入新牌位置右边的牌整体向右移动一个单位
    arr[j + 1] = arr[j];
   }
   arr[low] = temp; // 将抓到的牌插入手牌
  }
  return arr;
 }

 /**
  * 插入排序:越有序越快 1.从第一个元素开始,该元素可以认为已经被排序 2.取出下一个元素,在已经排序的元素序列中从后向前扫描
  * 3.如果该元素(已排序)大于新元素,将该元素移到下一位置 4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 5.将新元素插入到该位置后
  * 6.重复步骤2~5 数据结构 ---------- 数组 // 最差时间复杂度 ----
  * 最坏情况为输入序列是降序排列的,此时时间复杂度O(n^2) // 最优时间复杂度 ---- 最好情况为输入序列是升序排列的,此时时间复杂度O(n)
  * // 平均时间复杂度 ---- O(n^2) // 所需辅助空间 ------ O(1)
  *
  * @param arr
  * @return
  */
 private static int[] insertSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {// 趟数
   int temp = arr[i + 1];// 先定义一个带插入的数
   int j = i;// 从第j个位置从后往前找
   while (arr[j] > temp && j >= 0) {// 拿已经有序的数组的元素从右向左和带插入的元素比较
    arr[j + 1] = arr[j];// 比待插入的大就后移
    j--;
   }// 比它大的全部后移完毕
   arr[j + 1] = temp;// 把带插入的数放到前面
  }
  return arr;

 }

 /**
  * 选择排序优化版
  *
  * @param arr
  * @return
  */
 private static int[] selectSort2(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
   int k = i;
   for (int j = i; j < arr.length; j++) {
    if (arr[k] > arr[j]) {
     k = j;// 把最小的位置记着
    }
   }
   if (k != i) {
    swap(arr, k, i);
   }
  }
  return arr;
 }

 /**
  * 鸡尾酒排序---冒泡优化
  *
  * @param arr
  * @return
  */
 private static int[] jiweiSort(int[] arr) {
  int left = 0;
  int right = arr.length - 1;
  while (left < right) {
   for (int i = left; i < right; i++) {// 前半轮把大的排到后面
    if (arr[i] > arr[i + 1]) {
     swap(arr, i, i + 1);
    }
   }
   right--;
   for (int i = right; i > left; i--) {// 后半版把小的放到后面
    if (arr[i - 1] > arr[i]) {
     swap(arr, i - 1, i);
    }
   }
   left++;
  }
  return arr;
 }

 /**
  * 冒泡排序优化版
  *
  * @param arr
  * @return
  */
 private static int[] bubleSort2(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
   boolean flag = true;// 如果存在某一趟没有发生交换,则数组有序
   for (int j = 0; j < arr.length - 1 - i; j++) {
    if (arr[j] > arr[j + 1]) {
     swap(arr, j, j + 1);
     flag = false;
    }
   }
   if (flag) {
    break;
   }
  }
  return arr;
 }

 /**
  * 选择排序 一个去和后面的所有比较 数组 不稳定 时间复杂度 max 0(n^2) min 0(n^2) 空间复杂度 0(1)
  *
  * @param arr
  * @return
  */
 private static int[] selectSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {
   for (int j = i + 1; j < arr.length; j++) {
    if (arr[i] > arr[j]) {
     swap(arr, i, j);
    }
   }
  }
  return arr;
 }

 /**
  * 冒泡排序:外层是趟数,里层每次比较相邻的两个数,把大的换到后面 排数组,稳定,时间复杂度:max 0(n^2) min 0(n) avg
  * 0(n^2) 空间复杂度0(1)
  *
  * @param arr
  * @return
  */
 private static int[] bubleSort(int[] arr) {
  for (int i = 0; i < arr.length - 1; i++) {// 趟数
   for (int j = 0; j < arr.length - 1 - i; j++) {
    if (arr[j] > arr[j + 1]) {
     swap(arr, j, j + 1);
    }
   }
  }
  return arr;
 }

 /**
  * 交换方法
  *
  */
 private static int[] swap(int[] arr, int i, int j) {
  int temp;
  temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
  return arr;
 }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值