分类
- 插入排序
- 直接插入排序
- 希尔排序
- 交换排序
- 冒泡排序
- 快速排序
- 选择排序
- 直接选择排序
- 堆排序
- 归并排序
- 归并
- 归并排序
插入排序
直接插入排序
将待排序数组看作是左右两部分,左边为无序区,右边为有序区。排序过程就是将右边无序区中的元素逐个插入到左边有序区中,最后整个数组为有序区。
package test;
import java.util.Arrays;
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.directInsert(array);
System.out.println(Arrays.toString(array));
}
public static void directInsert(int[] array) {
int length = array.length;
int i; //当前要排序的元素,初始为第二个元素,默认第一个元素为有序区
int j; //有序区中要比较的元素,比较大小后移动或插入
int temp; //保存当前要排序的元素,从而空出一个位置用于移动有序区,再将该元素插入有序区的空位
for (i = 1; i < length; i++) {
temp = array[i];
j = i - 1; //空位左边的第一个元素
// 降序是找到比他大的元素,升序是找到比他小的元素
while (j >= 0 && array[j] > temp) {
array[j + 1] = array[j]; //如果该元素比他大,则将该元素后移,即升序
j--;
}
array[j + 1] = temp; //j+1就是空位
}
}
}
希尔排序
将待排序数组划分为若干组,在每组内进行直接插入排序,以使整个序列基本有序,然后再对整个序列进行直接插入排序
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.shell(array);
System.out.println(Arrays.toString(array));
}
public static void shell(int[] array) {
int length = array.length;
int i; //本组中要排序的元素
int j; //本组中空位的前一个元素
int temp; //保存本组要排序的元素,从而空出一个位置用于移动本组的元素,再将该元素插入本组的空位
int step; //将数组分为step组,step为相同组的元素的间隔步长
// 初始分组,最终分为一组
step = length / 2;
//step最终为1
while (step != 0) {
//对每组进行直接插入排序,i初始化为每组的第二个元素
for (i = step; i < length; i++) {
temp = array[i]; //留出空位用于移动有序区
j = i - step; //j为本组中空位的前一个元素
while (j >= 0 && array[j] > temp) {
array[j + step] = array[j]; //将大于temp的元素后移,即升序
j -= step; //向本组的有序区左边移动,j为空位前一个元素
}
array[j + step] = temp; //j+step为空位
}
//进行再次分组
step /= 2;
}
}
}
交换排序
冒泡排序
从一端开始,逐个比较相邻的两个元素,发现倒序即交换
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.bubble(array);
System.out.println(Arrays.toString(array));
}
public static void bubble(int[] array) {
int length = array.length;
int i; //泡的位置,即迭代次数,一共要冒length-1个泡,最后一个不用冒
int j; //指向当前正在排序的元素,一直指到上一个泡的下面
int temp; //用于交换位置时腾出空位
//泡依次冒到右边,即每次都是从无序区选一个最大值冒泡
for (i = (length - 1); i > 0; i--) {
for (j = 0; j < i; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
快速排序
首先选定一个元素作为中间元素,然后将数组中所有元素与该中间元素比较,将比中间元素小的放在数组前面,比中间元素大的放在数组后面,再以中间元素作为分界点,得到左右两部分数组,而中间元素位于正确位置上,不用参与后续排序。
然后再对左右两部分分别进行快速排序,即对得到的两个子数组再采用相同的方式来排序和划分,直到每个子数组仅有一个元素或为空数组为止,此时数组所有元素都有序。
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.quick(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
public static void quick(int[] array, int start, int end) {
int i; //基准左边的指针,指向正在排序的元素,也指向空位
int j; //基准右边的指针,指向正在排序的元素,也指向空位
int temp; //用于保存基准,一般是第一个元素,最后将基准放在中间
if (start < end) {
i = start;
j = end;
temp = array[i];
while (i < j) {
//由于以第一位为基准,空位在左边,则先从右边找到小于基准的元素,放在左边
while (i < j && array[j] > temp) {
j--;
}
if (i < j) {
array[i] = array[j]; //现在j是空位
i++;
}
//从左边找到大于基准的元素,然后放在右边的空位
while (i < j && array[i] < temp) {
i++;
}
if (i < j) {
array[j] = array[i]; //现在i是空位
j--;
}
}
//将基准放在空位
array[i] = temp;
//划分数组进行递归排序,基准不用进行排序
quick(array, start, i - 1);
quick(array, i + 1, end);
}
}
}
选择排序
直接选择排序
在每一趟排序中,在待排序数组中选出最小或最大的元素放在其最终的位置上
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.select(array);
System.out.println(Arrays.toString(array));
}
public static void select(int[] array) {
int length = array.length;
int i; //将要放置正确元素的位置,一共有length-1个,最后一个是正确的
int j; //指向正在排序的元素
int min; //初始化最小值,用于和后面元素比较,找到正确值进行交换位置
int temp; //交换位置时使用
for (i = 0; i < length - 1; i++) {
min = i;
for (j = i + 1; j < length; j++) {
if (array[min] > array[j]) {
min = j; //当前最小值
}
}
//如果最小值不等于最初值,则将换位置
if (min != i) {
temp = array[i];
array[i] = array[min];
array[min] = temp;
}
}
}
}
堆排序
堆排序的原理比之前的排序方法更复杂,这里就不多说了,已经有很多资料
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.heap(array);
System.out.println(Arrays.toString(array));
}
public static void heap(int[] array) {
int length = array.length;
int temp;
// 建立初始堆
for (int i = (length - 1) / 2; i >= 0; i--) {
sift(array, i, length - 1);
}
System.out.println(Arrays.toString(array));
// 逐步将根结点与末尾元素交换,并调整剩余数组为堆,即每次将最大值放在右边
for (int i = length - 1; i > 0; i--) {
temp = array[0];
array[0] = array[i];
array[i] = temp;
sift(array, 0, i - 1);
System.out.println(Arrays.toString(array));
}
}
// 调整数组中以k为根的子树序列为堆,最大下标为m
// 假定左右子树都是堆
private static void sift(int[] array, int k, int m) {
int i = k; // i表示当前根结点
int j = 2 * i + 1; // j指向当前根结点的左孩子
int temp;
// 保证i不是叶子
while (j <= m) {
// 让j指向左右孩子的最大者
if (j < m && array[j] < array[j + 1]) {
j += 1;
}
// 如果父结点最大,则建堆结束
if (array[i] >= array[j]) {
break;
} else {
temp = array[i];
array[i] = array[j]; // 大的孩子结点值上移
array[j] = temp; // 父结点下沉
i = j; // i表示新的根结点
j = 2 * i + 1; // j变为当前根结点的左孩子
}
}
}
}
归并排序
归并
将多个有序表合并成一个有序表
public class Sort {
public static void main(String[] args) {
int[] A = {0,1,2,3,4,5};
int[] B = {2,4,6,8,10,11};
array = Sort.merge(A, B);
System.out.println(Arrays.toString(array));
}
public static int[] merge(int[] A, int[] B) {
int aLength = A.length;
int bLength = B.length;
int[] C = new int[aLength + bLength];
int a = 0, b = 0, c = 0;
// 先按最短长度合并
while (a < aLength && b < bLength) {
if (A[a] > B[b]) {
C[c++] = B[b++];
} else {
C[c++] = A[a++];
}
}
// 填入剩余元素
while (a < aLength) {
C[c++] = A[a++];
}
while (b < bLength) {
C[c++] = B[b++];
}
return C;
}
}
归并排序
将整个表看成n个有序子表,然后两两归并
public class Sort {
public static void main(String[] args) {
int[] array = {2, 6, 3, 8, 23, 6, 2, -1, 14, 67, 4, 35, 90};
Sort.mergeSort(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
public static void mergeSort(int[] array, int low, int high) {
int mid = (low + high) / 2;
if (low < high) {
mergeSort(array, low, mid);
mergeSort(array, mid + 1, high);
merge(array, low, mid, high);
}
}
public static void merge(int[] array, 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 (array[i] < array[j]) {
temp[k++] = array[i++];
} else {
temp[k++] = array[j++];
}
}
// 填入剩余元素
while (i <= mid) {
temp[k++] = array[i++];
}
while (j <= high) {
temp[k++] = array[j++];
}
// 修改原数组
for (int m = 0; m < temp.length; m++) {
array[low + m] = temp[m];
}
}
}