
/**
* 1.直接插入排序(稳定)
* 原理:将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。
* 要点:设立哨兵,作为临时存储和判断数组边界之用。
*
*/
public class InsertSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
public static void insertSort(int[] array) {
// 从头部第一个当做已经排好序的,把后面的一个一个插入到已经排好序的列表中
for (int i = 1; i < array.length; i++) {
int temp = array[i];// temp为待插入的值
int j;
for (j = i - 1; j >= 0 && array[j] > temp; j--) {
// 将大于temp的值整体后移一个单位
array[j + 1] = array[j];
}
array[j + 1] = temp;
}
System.out.println("插入排序:" + Arrays.toString(array));
}
public static void main(String[] args) {
InsertSort.insertSort(NUMBERS);
}
}
/**
* 2.希尔排序
* 原理:又称缩小增量排序。先将序列按增量划分为元素个数相同的若干组,使用直接插入排序法进行排序,然后不断缩小增量直至为1,最后使用直接插入排序完成排序。
* 要点:增量的选择以及排序最终以1为增量进行排序结束。
*
*/
public class ShellSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
public static void shellSort(int[] array) {
int len = array.length;
while (len != 0) {
len = len / 2;
for (int i = 0; i < len; i++) {// 分组
for (int j = i + len; j < array.length; j += len) {
int end = j - len;// end为有序序列最后一位的位数
int temp = array[j];// temp为要插入的值
while (end >= 0 && temp < array[end]) {
array[end + len] = array[end];
end -= len;
}
array[end + len] = temp;
}
}
}
System.out.println("希尔排序:" + Arrays.toString(array));
}
public static void main(String[] args) {
ShellSort.shellSort(NUMBERS);
}
}
/**
* 3.直接选择排序
* 原理:将序列划分为无序和有序区,寻找无序区中的最小值和无序区的首元素交换,有序区扩大一个,循环最终完成全部排序。选择排序的基本思想是对待排序的记录序列进行n-1遍的处理,第i遍处理是将L[i..n]中最小者与L[i]交换位置。这样经过i遍处理之后,前i个记录的位置已经是正确的了。
*
*/
public class SelectSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
public static void selectSort(int[] array) {
int position;
for (int i = 0; i < array.length; i++) {
int j;
position = i;
int temp = array[i];
for (j = i + 1; j < array.length; j++) {
if (array[j] < temp) {
temp = array[j];
position = j;
}
}
array[position] = array[i];
array[i] = temp;
}
System.out.println("选择排序:" + Arrays.toString(array));
}
public static void main(String[] args) {
SelectSort.selectSort(NUMBERS);
}
}
/**
* 4.堆排序
* 原理:利用大顶堆或小顶堆思想,首先建立堆,然后将堆首与堆尾交换,堆尾之后为有序区。
* 要点:建堆、交换、调整堆
* 两个步骤:1.建堆
* 2.对顶与堆的最后一个元素交换位置
*
*/
public class HeapSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
public static void sort(int[] arr) {
// 1.构建大顶堆
for (int i = arr.length / 2 - 1; i >= 0; i--) {
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
// 2.调整堆结构 + 交换堆顶元素与末尾元素
for(int j = arr.length - 1; j > 0; j--){
swap(arr, 0, j);// 将堆顶元素与末尾元素进行交换
adjustHeap(arr, 0, j);// 重新对堆进行调整
}
}
/**
* 调整大顶堆(仅是调整过程,建立在大顶堆已构建的基础上)
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr, int i, int length) {
int temp = arr[i];// 先取出当前元素i
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {// 从i结点的左子结点开始,也就是2i+1处开始
if(k + 1 < length && arr[k] < arr[k + 1]) {// 如果左子结点小于右子结点,k指向右子结点
k++;
}
if (arr[k] > temp) {// 如果子节点大于父节点,将子节点值赋给父节点(不用进行交换)
arr[i] = arr[k];
i = k;
} else {
break;
}
}
arr[i] = temp;// 将temp值放到最终的位置
}
/**
* 交换元素
* @param arr
* @param a
* @param b
*/
public static void swap(int []arr, int a , int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
public static void main(String []args) {
sort(NUMBERS);
System.out.println("堆排序:" + Arrays.toString(NUMBERS));
}
}
/**
* 5.冒泡排序(稳定)
* 原理:将序列划分为无序和有序区,不断通过交换较大元素至无序区尾完成排序。
* 要点:设计交换判断条件,提前结束以排好序的序列循环。
*
*/
public class BubbleSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
public static void bubbleSort(int[] array) {
int temp;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j+1]) {
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
System.out.println("冒泡排序:" + Arrays.toString(array));
}
public static void main(String[] args) {
BubbleSort.bubbleSort(NUMBERS);
}
}
/**
* 6.快速排序
* 原理:不断寻找一个序列的中点,然后对中点左右的序列递归的进行排序,直至全部序列排序完成,使用了分治的思想。
* 要点:递归、分治
*
*/
public class QuickSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
// 分割
public static int partition(int[] a, int p, int r) {
int x = a[r];
int i = p;
int temp;
for (int j = p; j <= r; j++) {
if (a[j] < x) {
temp = a[j];
a[j] = a[i];
a[i] = temp;
i++;
}
}
temp = a[r];
a[r] = a[i];
a[i] = temp;
return i;
}
public static void quickSort(int[] a, int p, int r) {
if (p < r) {
int q = partition(a, p, r);
quickSort(a, p, q - 1);
quickSort(a, q + 1, r);
}
}
public static void main(String[] args) {
quickSort(NUMBERS, 0, 9);
System.out.println("快速排序:" + Arrays.toString(NUMBERS));
}
}
/**
* 7.归并排序(稳定)
* 原理:将原序列划分为有序的两个序列,然后利用归并算法进行合并,合并之后即为有序序列。
* 要点:归并、分治
*/
public class MergeSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
// 归并
public static void merge(int[] a, int low, int mid, int high) {
int[] temp = new int[high - low + 1];
int i = low;// 左指针
int j = mid + 1;// 右指针
int k = 0;
// 把较小的数先移到新数组中
while (i <= mid && j <= high) {
if (a[i] < a[j]) {
temp[k++] = a[i++];
} else {
temp[k++] = a[j++];
}
}
// 把左边剩余的数移入数组
while (i <= mid) {
temp[k++] = a[i++];
}
// 把右边边剩余的数移入数组
while (j <= high) {
temp[k++] = a[j++];
}
// 把新数组中的数覆盖a数组
for (int m = 0; m < temp.length; m++) {
a[m + low] = temp[m];
}
}
public static void mergeSort(int[] a, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
// 左边
mergeSort(a, low, mid);
// 右边
mergeSort(a, mid + 1, high);
// 左右归并
merge(a, low, mid, high);
// System.out.println(Arrays.toString(a));
}
}
public static void main(String[] args) {
mergeSort(NUMBERS, 0, NUMBERS.length - 1);
System.out.println("归并排序:" + Arrays.toString(NUMBERS));
}
}
/**
* 8.基数排序(稳定)
* 原理:将数字按位数划分出n个关键字,每次针对一个关键字进行排序,然后针对排序后的序列进行下一个关键字的排序,循环至所有关键字都使用过则排序完成。
* 要点:对关键字的选取,元素分配收集。
*
*/
public class RadixSort {
// 排序原始数据
private static final int[] NUMBERS = {62, 99, 98, 54, 56, 17, 18, 23, 34, 15};
private static void radixSort(int[] array, int d) {
int n = 1;// 代表位数对应的数:1,10,100...
int k = 0;// 保存每一位排序后的结果用于下一位的排序输入
int length = array.length;
// 排序桶用于保存每次排序后的结果,这一位上排序结果相同的数字放在同一个桶里
int[][] bucket = new int[10][length];
int[] order = new int[length];// 用于保存每个桶里有多少个数字
while (n < d) {
for (int num : array) {//将数组array里的每个数字放在相应的桶里
int digit = (num / n) % 10;
bucket[digit][order[digit]] = num;
order[digit]++;
}
// 将前一个循环生成的桶里的数据覆盖到原数组中用于保存这一位的排序结果
for (int i = 0; i < length; i++) {
if (order[i] != 0) {// 这个桶里有数据,从上到下遍历这个桶并将数据保存到原数组中
for (int j = 0; j < order[i]; j++) {
array[k] = bucket[i][j];
k++;
}
}
order[i] = 0;// 将桶里计数器置0,用于下一次位排序
}
n *= 10;
k = 0;// 将k置0,用于下一轮保存位排序结果
}
}
public static void main(String[] args) {
radixSort(NUMBERS, 100);
System.out.println("基数排序:" + Arrays.toString(NUMBERS));
}
}