public class Sort {
public Sort() {
System.out.println("sort constructor");
}
public static void main(String[] args) {
//
int[] a = {1000, 11, 10, 55, 1, 78, 100, 111, 56, 45, 79, 90, 345};
//System.out.println(8/3);
System.out.println("排序之前");
output(a);
//insertSort(a);
//shellSort(a);
//selectSort(a);
//heapSort(a);
//bubbleSort(a);
//quickSort(a, 0, a.length - 1);
//mergeSort(a, 0, a.length - 1, new int[a.length]);
radisSort(a,10);
System.out.println("排序之后");
output(a);
}
/**
* 直接插入排序
*
* 1. 从第一个元素开始,该元素可以认为已经被排序
* 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描
* 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置
* 4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
* 5. 将新元素插入到该位置后
* 6. 重复步骤2~5
*
* @param array 待排序数组
*/
public static void insertSort(int[] array) {
int i = 1;
while (i < array.length) {
int temp = array[i];
int j;
for (j = i - 1; j >= 0; j--) {
if (array[j] > temp) {
array[j + 1] = array[j];
} else {
break;
}
}
array[j + 1] = temp;
i++;
}
}
/**
* 希尔排序(Wiki官方版)
*
* 1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;(注意此算法的gap取值)
* 2. 按增量序列个数k,对序列进行k 趟排序;
* 3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。
*
* @param array 待排序数组
*/
public static void shellSort(int[] array) {
int gap = 1, i, j, len = array.length;
int temp;
while (gap < len / 3) {
// <O(n^(3/2)) by Knuth,1973>: 1, 4, 13, 40, 121, ...
gap = gap * 3 + 1;
}
for (; gap > 0; gap /= 3) {
//直接插入排序
for (i = gap; i < len; i++) {
temp = array[i];
//从后向前依次进行比较,若值大于temp,则向后移位
for (j = i - gap; j >= 0 && array[j] > temp; j -= gap) {
array[j + gap] = array[j];
}
//找到小于等于temp的位置,插入temp,此处j+gap的原因是for中j-=gap
array[j + gap] = temp;
}
}
}
/**
* 选择排序
*
* 1. 从待排序序列中,找到关键字最小的元素;
* 2. 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;
* 3. 从余下的 N - 1 个元素中,找出关键字最小的元素,重复①、②步,直到排序结束。
*
* @param array 待排序数组
*/
public static void selectSort(int[] array) {
for (int i = 0; i < array.length; i++) {
int minIdx = i;
for (int j = i + 1; j < array.length; j++) {
//此处需要注意,array[minIdx]不要写成array[j]
if (array[j] < array[minIdx]) {
minIdx = j;
}
}
if (minIdx != i) {
int temp = array[minIdx];
array[minIdx] = array[i];
array[i] = temp;
}
}
}
/**
* 堆排序
*
* 1. 先将初始序列K[1..n]建成一个大顶堆, 那么此时第一个元素K1最大, 此堆为初始的无序区.
* 2. 再将关键字最大的记录K1 (即堆顶, 第一个元素)和无序区的最后一个记录 Kn 交换, 由此得到新的无序区K[1..n−1]和有序区K[n], 且满足K[1..n−1].keys⩽K[n].key
* 3. 交换K1 和 Kn 后, 堆顶可能违反堆性质, 因此需将K[1..n−1]调整为堆. 然后重复步骤②, 直到无序区只有一个元素时停止.
*
* @param arr 待排序数组
*/
public static void heapSort(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) {
//先取出当前元素i
int temp = arr[i];
//从i结点的左子结点开始,也就是2i+1处开始
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
//如果左子结点小于右子结点,k指向右子结点
if (k + 1 < length && arr[k] < arr[k + 1]) {
k++;
}
//如果子节点大于父节点,将子节点值赋给父节点
if (arr[k] > temp) {
arr[i] = arr[k];
i = k;
} else {
break;
}
}
//将temp值放到最终的位置
arr[i] = temp;
}
/**
* 冒泡排序
* 第一次次将最大的数冒泡到最后,第二次将第二大的数冒泡到倒数第二个位置,以此类推
*
* @param array
*/
public static void bubbleSort(int[] array) {
//外层控制冒泡次数
for (int i = 0; i < array.length - 1; i++) {
//-i是控制循环完成的数据不再进行比较
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
swap(array, j, j + 1);
}
}
}
}
/**
* 快速排序
* 选定一个基准值(一般是第一个元素),两个指针,一个前指针一个后指针
* 后指针从后向前遍历,遇到第一个小于基准值的位置停下
* 前指针从前向后遍历,遇到第一个大于基准值的位置停下
* 交换两个指针上的元素,直到j=i
*
* @param array
* @param left
* @param right
*/
public static void quickSort(int[] array, int left, int right) {
if (left > right) {
return;
}
int temp = array[left];
int j = right;
int i = left;
while (i < j) {
//顺序很重要,要先从右边开始找
//当i停下来时,a[i]的值大于基准数或走到了尽头。
//当i没有走到尽头,也就是说i找到了一个大于基准的数,
//接着j开始向左走,企图寻找一个小于基准的数,但是存在i < j这个条件的限制,j有可能没找到小于基准的数时就被迫停下来了,此时i==j的位置与基准数交换位置,结果就会出现错误。
//当然,我们想从左开始并且正确也是可以的
//需要改基准值为数组最右边:
while (array[j] >= temp && i < j) {
j--;
}
while (array[i] <= temp && i < j) {
i++;
}
if (i < j) {
swap(array, i, j);
}
}
//最终将基准数归位
array[left] = array[i];
array[i] = temp;
quickSort(array, left, i - 1);
quickSort(array, i + 1, right);
}
/**
* 归并排序
* 将数组分成很小的单元,每个单元排序后,再将这两个单元合成一个有序的序列
* 递归完成
*
* @param array
* @param left
* @param right
* @param temp
*/
public static void mergeSort(int[] array, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(array, left, mid, temp);
mergeSort(array, mid + 1, right, temp);
merge(array, left, right, mid, temp);
}
}
public static void merge(int[] array, int left, int right, int mid, int[] temp) {
int i = left;
int j = mid + 1;
int t = 0;
while (i <= mid && j <= right) {
if (array[i] <= array[j]) {
temp[t++] = array[i++];
} else {
temp[t++] = array[j++];
}
}
while (i <= mid) {
temp[t++] = array[i++];
}
while (j <= right) {
temp[t++] = array[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while (left <= right) {
array[left++] = temp[t++];
}
}
/**
* 基数排序
* 将整数按位数切割成不同的数字,然后按每个位数分别比较
*
* @param array
* @param radix 基数:十进制为10radix = 10;
*/
public static void radisSort(int[] array, int radix) {
int[][] bucket = new int[radix][array.length];
int maxDigit = getMaxDigit(array);
int divisor = 1;
int currentDigit = 1;
while (currentDigit <= maxDigit) {
// 用来计数:数组counter[i]用来表示该位是i的数的个数
//因为每个位置上可能有多个数据,因此使用一个数组记录位置上的元素数
int[] counter = new int[radix];
// 将array中元素分布填充到bucket中,并进行计数
for (int i = 0; i < array.length; i++) {
int which = (array[i] / divisor) % radix;
bucket[which][counter[which]] = array[i];
counter[which]++;
}
int index = 0;
// 根据bucket中收集到的array中的元素,根据统计计数,在array中重新排列
for (int i = 0; i < radix; i++) {
if (counter[i] != 0) {
for (int j = 0; j < counter[i]; j++) {
array[index] = bucket[i][j];
index++;
}
}
counter[i] = 0;
}
divisor *= radix;
currentDigit++;
}
}
public static int getMaxDigit(int[] array) {
int maxNum = getMaxNum(array);
int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE};
for (int i = 0; ; i++) {
if (maxNum <= sizeTable[i]) {
return i + 1;
}
}
}
public static int getMaxNum(int[] array) {
int maxNum = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i] > maxNum) {
maxNum = array[i];
}
}
return maxNum;
}
/**
* 交换元素
*
* @param arr
* @param a
* @param b
*/
public static void swap(int[] arr, int a, int b) {
arr[a] ^= arr[b];
arr[b] ^= arr[a];
arr[a] ^= arr[b];
}
//输出打印
public static void output(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + (i == arr.length - 1 ? "" : ","));
}
System.out.print("\n");
}
}
常见排序算法代码及时间复杂度整理(java)-已测试
最新推荐文章于 2022-03-22 20:02:38 发布