一.冒泡排序
1.基本思想
冒泡排序(Bubble Sort)是一种简单的排序算法,其基本思想是通过反复比较相邻的元素并交换位置,将最大(或最小)的元素逐步 “冒泡” 到序列的末尾(或开头),从而实现排序。
2.代码实现
public static void bubbleSort(int[] array) {
for (int i = 0; i < array.length; i++) {
boolean flag = false;
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) { //如果修改为>=就是不稳定的,因此冒泡排序是不稳定的
swap(array, j, j + 1);
flag = true;
}
}
if (!flag) { //如果前趟排序不进行交换,证明已经排序完成,提前结束
break;
}
}
}
3.特性总结
1. 时间复杂度:O(N^2)
2. 空间复杂度:O(1)
3. 稳定性:稳定
二.快速排序
1.基本思想
任取待排序元素序列中的某元 素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有 元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
2.代码实现
1.无优化
1.Hoare法
public static void quickSort(int[] array) {
quick(array, 0, array.length-1);
}
private static void quick(int[] array, int start, int end) {
if (start >= end) {
return;
}
int pivot = partition(array, start, end);
quick(array, start, pivot-1);
quick(array, pivot+1, end);
}
private static int partition(int[] array, int left, int right) {
int tmp = array[left];
int tmpLeft = left;
while (left < right) {
while (left < right && array[right] >= tmp) {
right--;
}
while (left < right && array[left] <= tmp) {
left++;
}
swap(array,left,right);
}
swap(array,left,tmpLeft);
return left;
}
2.挖坑法
public static void quickSort(int[] array) {
quick(array, 0, array.length-1);
}
private static void quick(int[] array, int start, int end) {
if (start >= end) {
return;
}
int pivot = partition(array, start, end);
quick(array, start, pivot-1);
quick(array, pivot+1, end);
}
private static int partition(int[] array, int left, int right) {
int tmp = array[left];
while (left < right) {
while (left < right && array[right] >= tmp) {
right--;
}
array[left] = array[right];
while (left < right && array[left] <= tmp) {
left++;
}
array[right] = array[left];
}
array[left] = tmp;
return left;
}
3.前后指针法
public static void quickSort(int[] array) {
quick(array, 0, array.length-1);
}
private static void quick(int[] array, int start, int end) {
if (start >= end) {
return;
}
int pivot = partition(array, start, end);
quick(array, start, pivot-1);
quick(array, pivot+1, end);
}
private static int partition(int[] array, int left, int right) {
int prev = left;
int cur = left+1;
while (cur <= right) {
if (array[cur] < array[left] && array[++prev] != array[cur]) {
swap(array,cur,prev);
}
cur++;
}
swap(array,prev,left);
return prev;
}
2.优化
1.快速排序优化
1.1 三数取中法
从数组的起始位置、中间位置和末尾位置选取三个元素,然后对这三个元素进行排序,取排序后中间的那个元素作为基准元素。避免数组有序时时间复杂度为最坏情况O(N^2)。
private static void quick(int[] array, int start, int end) {
if (start >= end) {
return;
}
int midIndex = getMiddleNum(array,start,end);
swap(array, start, midIndex);
int pivot = partition(array, start, end);
quick(array, start, pivot-1);
quick(array, pivot+1, end);
}
private static int getMiddleNum(int[] array, int left, int right) {
int mid = (left + right) / 2;
if (array[left] < array[right]) {
if (array[mid] < array[left]){
return left;
} else if (array[mid] > array[right]) {
return right;
} else {
return mid;
}
} else {
if (array[mid] < array[right]) {
return right;
} else if (array[mid] > array[left]) {
return left;
} else {
return mid;
}
}
}
1.2递归到小的子区间时使用插入排序
private static void quick(int[] array, int start, int end) {
if (start >= end) {
return;
}
if (end - start + 1 <= 7) {
insertSortRange(array,start,end);
return;
}
int midIndex = getMiddleNum(array,start,end);
swap(array, start, midIndex);
int pivot = partition(array, start, end);
quick(array, start, pivot-1);
quick(array, pivot+1, end);
}
private static void insertSortRange(int[] array, int start, int end) {
for (int i = start+1; i < end; i++) {
int tmp = array[i];
int j = i - 1;
for (; j >= start ; j--) {
if (array[j] > tmp) {
array[j + 1] = array[j];
} else {
array[j + 1] = tmp;
break;
}
}
array[j + 1] = tmp;
}
}
2.非递归实现快速排序
public static void quickSort(int[] array) {
quickNor(array, 0, array.length-1);
}
private static void quickNor(int[] array, int start, int end) {
Deque<Integer> stack = new ArrayDeque<>();
int pivot = partition(array,start,end);
if (pivot > start + 1) { //至少有两个元素
stack.push((start));
stack.push(pivot - 1);
}
if (end - 1 > pivot) { //至少有两个元素
stack.push(pivot + 1);
stack.push(end);
}
while (!stack.isEmpty()) {
end = stack.pop();
start = stack.pop();
pivot = partition(array,start,end);
if (pivot > start + 1) { //至少有两个元素
stack.push((start));
stack.push(pivot - 1);
}
if (end - 1 > pivot) { //至少有两个元素
stack.push(pivot + 1);
stack.push(end);
}
}
}
3.特性总结
1. 时间复杂度:O(N*logN)
2. 空间复杂度:O(logN)
3. 稳定性:不稳定