package cn.hucn;
/**
* 排序算法的整理
*
* @author HuaHua
* @v2017-11-9@上午10:04:47
* @Sortfunction.java
*/
* 排序算法的整理
*
* @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);//鸡尾酒排序
* @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[]=selectSort2(arr);//选择2
// int res[]=insertSort(arr);//插入排序
// int res[] = binaryInsertSort(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);
}
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;
}
* 堆排序
* // 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ----
* 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;
}
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);
}
}
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;
}
* 快速排序 分类 ------------ 内部比较排序 // 数据结构 --------- 数组 // 最差时间复杂度 ----
* 每次选取的基准都是最大(或最小)的元素,导致每次只划分出了一个分区,需要进行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;
}
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;
}
* 归并排序 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组 // 最差时间复杂度 ----
* 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];
}
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(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;
}
* 二分插入排序 前提:数列有序 // 分类 -------------- 内部比较排序 // 数据结构 ---------- 数组
* //最差时间复杂度 ---- 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;
* 插入排序:越有序越快 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[] 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[] 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;
}
* 冒泡排序优化版
*
* @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^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;
}
* 冒泡排序:外层是趟数,里层每次比较相邻的两个数,把大的换到后面 排数组,稳定,时间复杂度: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;
}
* 交换方法
*
*/
private static int[] swap(int[] arr, int i, int j) {
int temp;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
}