排序
插入排序
直接插入排序
package ccnu.allSort;
public class InsertSort {
/**
* 在有序子序列中寻找插入位置时,只要满足前面的元素要比当前需要插入元素要大时,就要将这个前面的元素后移,直到
* 当前判断的这个元素小于等于当前需要插入元素时,就可以将需要插入的这个元素插入到当前判断的元素的后面即可,当所
* 有需要插入的元素插入完毕后,整个表就将是有序表
*
* @param arr
* 待排序列
*/
public static void insertSort(int[] arr) {
int i, ii, temp;
for (i = 1; i < arr.length; i++) {
temp = arr[i];
for (ii = i - 1; ii >= 0 && arr[ii] > temp; ii--) {
arr[ii + 1] = arr[ii];
}
arr[ii + 1] = temp;
}
}
}
折半插入排序
package ccnu.allSort;
public class InsertSort2 {
/**
* 折半插入排序是首先将当前要插入的元素的位置在前面的有序序列中找到,然后将所有元素后移,最后用将待插入元素插入到找到的位置上
* 直到所有需要插入的元素插入完毕,整个表就是有序表(与直接插入排序(一边找一边后移)不同是,它是首先找到插入位置,一次性后移,然后将需要插入的元素插入到找到的位置上)
*
* @param arr
* 待排序列
*/
public static void insertSort2(int[] arr) {
int i, ii, low, mid, high, temp;
for (i = 1; i < arr.length; i++) {
temp = arr[i];
low = 0;
high = i - 1;
while (low <= high)
{
mid = (low + high) / 2;
if (arr[mid] > arr[i]) {
high = mid - 1;
} else if (arr[mid] == arr[i]) {
high = mid;
break;
} else {
low = mid + 1;
}
}
for (ii = i - 1; ii >= high + 1; ii--) {
arr[ii + 1] = arr[ii];
}
arr[high + 1] = temp;
}
}
}
希尔排序
package ccnu.allSort;
public class ShellSort {
/**
*
* 由于直接插入排序算法适用于基本有序的排序表(因为基本有序就会使得前后移动的次数减少),那么就可以将待排序表分成若干个子表,进行各自排序.
* 开始取一个步长d,按照d进行分组(必然会将整个待排序列分为d组),然后将各个组按照直接插入排序进行排序,当每一组均自身有序时,步长减少,再次分组排序,最后当步长
* 为1时(此时整个序列已然基本有序了),再次进行直接插入排序就会使得整个序列有序
*
* @param arr
* 待排序列
*/
public static void shellSort(int[] arr) {
int d;
int i, ii, temp;
for (d = arr.length / 2; d >= 1; d /= 2) {
for (i = d; i < arr.length; i++) {
temp = arr[i];
for (ii = i - d; ii >= 0 && arr[ii] > temp; ii -= d) {
arr[ii + d] = arr[ii];
}
arr[ii + d] = temp;
}
}
}
}
选择排序
简单选择排序
package ccnu.allSort;
public class SelectSort {
/**
* 每次从无序的子序列(当然起初无序子序列就是原待排子序列本身)中找出一个最小的元素与当前这个无序子序列的第一个元素进行交换,直到无序子序列为空,也就是所有元素均排好序
*
* @param arr
* 待排序列
*/
public static void selectSort(int[] arr) {
int i, ii, temp;
int min;
for (i = 0; i < arr.length; i++) {
min = i;
temp = arr[i];
for (ii = i + 1; ii < arr.length; ii++) {
if (arr[ii] < arr[min]) {
min = ii;
}
}
arr[i] = arr[min];
arr[min] = temp;
}
}
}
堆排序
package ccnu.allSort;
public class HeapSort {
/**
* 堆排序是将一个待排序表按照一棵完全二叉树的顺序存储结构进行存储,再利用完全二叉树中的双亲节点与其子节点的内在关系在当前的无序区选择最大(最小)元素
* 首先将这个无序表(完全二叉树的顺序存储结构)中的所有根节点依次进行大根堆调整,直到整个表满足大根堆性质,接着就可以取堆顶元素(当前无序表最大元素)与
* 当前无序表的最后一个元素进行交换,此时减少一个元素(与上一次相比)的无序表已破坏大根堆性质,就要继续调整这个无序表,调整好之后,再次交换,再次调整,直
* 到无序表只剩下一个元素为止
*
* @param arr
* 待排序列
*/
public static void heapSort(int[] arr) {
buildMaxHeap(arr);
for (int i = arr.length - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adjust(arr, 0, i);
}
}
private static void buildMaxHeap(int[] arr) {
for (int i = arr.length / 2; i >= 0; i--) {
adjust(arr, i, arr.length);
}
}
/**
*
* @param arr
* 待调整的序列
* @param k
* 当前需要调整的根节点的索引
* @param length
* 对于整个序列中待调整元素的个数(当然当第一次对整个序列建立大根堆的时候,每一次调整的元素个数应当是arr.length,当整个序列的初始大根堆建立完成
* 后,将最大元素(当前序列的堆顶)与当前无序序列的最后一个元素交换后,就会破坏大根堆性质,就需要重新调整,此时需要调整的元素个数必然要比上一次调整的个数少一个(堆
* 顶元素与当前无序序列的最后一个元素交换后,从这个索引位置到整个序列最后一个索引均有序))
*/
private static void adjust(int[] arr, int k, int length) {
for (int i = 2 * k; i < length; i *= 2) {
if (i < (length - 1) && arr[i] < arr[i + 1]) {
i++;
}
if (arr[k] >= arr[i]) {
break;
} else {
int temp = arr[k];
arr[k] = arr[i];
arr[i] = temp;
k = i;
}
}
}
}
交换排序
冒泡排序
package ccnu.allSort;
import java.util.List;
public class BubbleSort /* implements java.util.Comparator<String> */ {
public static void bubbleSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
boolean isSorted = true;
for (int ii = 0; ii < arr.length - i; ii++) {
if (arr[ii] > arr[ii + 1]) {
isSorted = false;
int temp = arr[ii];
arr[ii] = arr[ii + 1];
arr[ii + 1] = temp;
}
}
if (isSorted) {
break;
}
}
}
}
快速排序
package ccnu.allSort;
public class QuickSort {
/**
* 首先取一个基准值(一般取待排序列的第一个元素),将比这个基准值不大的放在它的左边,比这个基准值不小的放在它的右边,这样就可以将这个基准值放在整个序列的最终位置上,接着
* 以这个基准值的索引将这个序列分割为两个子表,前后这两个子表再次进行同样的分割,依此分割下去,直到所有子表不能分割(前索引不小于后索引)
*
* @param arr
* 待排序列
* @param low
* 待排序列的最小索引
* @param high
* 待排序列的最大索引
*/
public static void quickSort(int[] arr, int low, int high) {
int indexPivot;
if (low < high) {
indexPivot = partition(arr, low, high);
quickSort(arr, low, indexPivot - 1);
quickSort(arr, indexPivot + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[low];
while (low < high)
{
while (low < high && arr[high] >= pivot) {
high--;
}
arr[low] = arr[high];
while (low < high && arr[low] <= pivot) {
low++;
}
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
}
快速排序优化建议
- 基准的选取可以是从索引low,(low+high)/2,high三个中选取中间大小的,而不总是low处,这样就可以尽量避免递归树的不平衡
int mid = (low + high) / 2;
int[] tmp = new int[]{arr[low], arr[mid], arr[high]};
Arrays.sort(tmp);
int pivot = tmp[1];
- 当某一次递归时,其处理数组中的元素个数(high-low+1)小于某个设定的值(我们假定这个阈值为MAX_LENGTH=7)就不需要再使用递归了,而是直接使用直接插入排序,这样效率会更高
if((high - low + 1) > MAX_LENGTH){
// 使用递归
// ...
}else{
// 直接使用插入排序
// ...
}
- 使用尾递归,而不是双递归
while(low < high){
indexPivot = partition(arr, low, high);
quickSort(arr, low, pivot - 1);
low = pivot + 1;
}
- 当通过某个基准值进行将当前待排序列分为两个子部分后,应当先递归序列长度较短的子序列,然后再递归子序列长度较长的那一部分,这样可以降低递归栈的深度
if(indexPivot - low <= high - indexPivot){
quickSort(arr, low, indexPivot - 1);
quickSort(arr, indexPivot + 1, high);
}else{
quickSort(arr, indexPivot + 1, high);
quickSort(arr, low, indexPivot - 1);
}
归并排序
package ccnu.allSort;
public class MergeSort {
/**
* 对于待排序中的arr.length个元素,可以首先将这个待排序表不断的分割,直到将整个表分割为arr.length个长度为1的子表,那么此时我们可以看作这arr.length个子表均是有
* 序的,接着就可以将这些有序子表两两归并为一个有序子表,如此进行下去,直到归并为一个长度为arr.length的表,此时就可以得到原表的有序表(对于一个无序表arr[low,high]来
* 说,可以将其分为两个部分,然后将前后两个部分归并为一个表(在将前后两个子表归并为一个子表前,要保证这两个子表必须自身已有序,所以就要将表不断的分割为长度为1的子表,此时自然有序了))
*
* @param arr
* 当前待排序表
* @param low
* 当前待排序中的第一个索引
* @param high
* 当前待排序表中的最后一个索引
*/
public static void mergeSort(int[] arr, int low, int high) {
if (low < high) {
int mid = (low + high) / 2;
mergeSort(arr, low, mid);
mergeSort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
}
private static void merge(int[] arr, int low, int mid, int high) {
int[] temp = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
temp[i] = arr[i];
}
int i = low;
int j = mid + 1;
int k = i;
while (i <= mid && j <= high) {
if (temp[i] <= temp[j]) {
arr[k++] = temp[i++];
} else {
arr[k++] = temp[j++];
}
}
while (i <= mid) {
arr[k++] = temp[i++];
}
while (j <= high) {
arr[k++] = temp[j++];
}
}
}