package Sort;
public class sort {
// https://www.cnblogs.com/onepixel/articles/7674659.html
public static void main(String[] args) {
int[] arr = { 2, 6, 3, 5, 7, 3, 6, 8 };
HeapSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
// 冒泡
// 每次比较相邻的元素,如果第一个比第二个大就交换他们两个
// 这样交换到最后,最后的元素是最大的
// 针对除了最后一个元素以外的所有元素重复以上步骤
public static void BubbleSort(int[] arr) {
int len = arr.length;
for (int i = 0; i < len - 1; i++) {
for (int j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = temp;
}
}
}
}
// 选择排序
// 在未排序序列中找到最小的元素,放到排序序列的起始位置,
// 然后再从剩余未排序元素中继续寻找最小的元素,放在已排序的末尾
public static void SelectionSort(int[] arr) {
int len = arr.length;
int min = 0;
for (int i = 0; i < len - 1; i++) {
min = i;
for (int j = i + 1; j < len; 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 InsertSort(int[] arr) {
int len = arr.length;
for (int i = 1; i < len; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j - 1]) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
// 希尔排序
// 插入排序的改进版,会优先比较距离较远的元素
public static void Shell(int[] arr) {
int n = arr.length;
int h = 1;
while (h < n / 3) {
// 1,4,13……
h = h * 3 + 1;
}
while (h >= 1) {
for (int i = h; i < n; i++) {
for (int j = i; j >= h; j--) {
if (arr[j] < arr[j - h]) {
int temp = arr[j];
arr[j] = arr[j - h];
arr[j - h] = temp;
}
}
h = h / 3;
}
}
}
// 归并排序
// 把长度为n的输入序列分成两个长度为n/2的子序列
// 对这两个子序列分别采用归并排序
// 将两个排序好的子序列合并成一个最终的排序序列
public static void MergeSort(int[] arr, int start, int end) {
if (arr == null || start >= end) {
return;
}
int middle = (start + end) / 2;
// 递归
MergeSort(arr, start, middle);
MergeSort(arr, middle + 1, end);
// 归并
Merge(arr, start, middle, end);
}
public static void Merge(int[] arr, int start, int mid, int end) {
int[] array = new int[end + 1]; // 定义一个临时数组,用来存储排序后的结果
int k = start; // 临时数组的索引
int i = start;
int j = mid + 1;
// 取出最小值放入临时数组中
while (i <= mid && j <= end) {
array[k++] = arr[i] > arr[j] ? arr[j++] : arr[i++];
}
// 若还有段序列不为空,则将其加入临时数组末尾
while (i <= mid) {
array[k++] = arr[i++];
}
while (j <= end) {
array[k++] = arr[j++];
}
// 将临时数组中的值copy到原数组中
for (int m = start; m <= end; m++) {
arr[m] = array[m];
}
}
// 快速排序
// 从数列中挑选一个数作为基准
// 所有元素比基准小的放在基准前面,比基准大的放在基准后面,退出后,基准在中间位置
// 递归
public static void QuickSort(int[] a, int start, int end) {
// 1,找到递归算法的出口
if (start > end) {
return;
}
// 2, 存
int i = start;
int j = end;
// 3,key
int key = a[start];
// 4,完成一趟排序
while (i < j) {
// 4.1 ,从右往左找到第一个小于key的数
while (i < j && a[j] > key) {
j--;
}
// 4.2 从左往右找到第一个大于key的数
while (i < j && a[i] <= key) {
i++;
}
// 4.3 交换
if (i < j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
// 4.4,调整key的位置
int temp = a[i];
a[i] = a[start];
a[start] = temp;
// 5, 对key左边的数快排
QuickSort(a, start, i - 1);
// 6, 对key右边的数快排
QuickSort(a, i + 1, end);
}
// 堆排序
// 父节点的键值大于子节点
// 构建大根堆:将array看成完全二叉树的顺序存储结构
private static int[] buildMaxHeap(int[] array) {
// 从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆
for (int i = (array.length - 2) / 2; i >= 0; i--) {
adjustDownToUp(array, i, array.length);
}
return array;
}
// 将元素array[k]自下往上逐步调整树形结构
private static void adjustDownToUp(int[] array, int k, int length) {
int temp = array[k];
for (int i = 2 * k + 1; i < length - 1; i = 2 * i + 1) { // i为初始化为节点k的左孩子,沿节点较大的子节点向下调整
if (i< length && array[i] < array[i + 1]) { // 取节点较大的子节点的下标
i++; // 如果节点的右孩子>左孩子,则取右孩子节点的下标
}
if (temp >= array[i]) { // 根节点 >=左右子女中关键字较大者,调整结束
break;
} else { // 根节点 <左右子女中关键字较大者
array[k] = array[i]; // 将左右子结点中较大值array[i]调整到双亲节点上
k = i; // 【关键】修改k值,以便继续向下调整
}
}
array[k] = temp; // 被调整的结点的值放人最终位置
}
// 堆排序
public static void HeapSort(int[] array) {
array = buildMaxHeap(array); // 初始建堆,array[0]为第一趟值最大的元素
for (int i = array.length - 1; i >=1; i--) {
int temp = array[0]; // 将堆顶元素和堆低元素交换,即得到当前最大元素正确的排序位置
array[0] = array[i];
array[i] = temp;
adjustDownToUp(array, 0, i); // 整理,将剩余的元素整理成堆
}
}
}