交换排序:
- 包括冒泡排序和快速排序
冒泡排序
算法思想:
- 逐个两两比较大小,若前一个元素大于后一个元素则使二者交换位置。如此往复,完成一趟遍历即可使得一个元素(最大值)归位。
效率及稳定性:
- 时间复杂度最好是O(n),最坏是O(n^2),平均为O(n^2),空间复杂度为O(1),是一种稳定的排序算法;
- 就地排序,每趟产生全局有序区;
适用场景:
- 适用元素较少的情况下,元素太多的话,交换和比较次数都会很多,影响效率,元素多的情况适合用快速排序.
- 当数组基本有序的情况下适合使用冒泡排序和直接插入排序,它们在基本有序的情况下排序的时间复杂度接近O(n)
示例代码:
private static void Sort(int[] a) {
boolean tag;//用于判断实时的数组是否已经有序
for (int i = 0; i < a.length - 1; i++) {
//总共需要a.length-1趟排序,因为每趟只归位一个元素,需将a.length-1个元素归位即可使整个数组有序
tag = true;//每趟开始之前将标志置为true
for (int j = 0; j < a.length - 1- i; j++) {
//第i趟只需要比较a.length-i-1次,如:第一趟只需要比较a.length-1次
if (a[j] > a[j + 1]) {
int temp = 0;
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
tag = false;//发生交换就将标志位置为false,表示当前数组还没有完全有序;
}
}
if (tag) {//进行一趟完整的排序后没有发生交换则说明已经排序完成;
return;//结束排序
}
}
}复制代码
快速排序
算法思想:
- 在要排的数(比如数组A)中选择一个中心值key(比如A[0]),通过一趟排序将数组A分成两部分,其中以key为中心,key右边都比key大,key左边的都key小,然后对这两部分分别重复这个过程,直到整个有序。 整个快排的过程就简化为了一趟排序的过程,然后递归调用就行了。
效率及稳定性:
- 快速排序的最好情况下的时间复杂度为O(N*log2N),最坏情况下的时间复杂度为O(N^2),平均的时间复杂度为O(N*log2N)。空间复杂度为O(1),属于不稳定排序。
- 每趟归位一个元素;
适用场景:
- 快速排序适用于数据杂乱无章的场景,而且越乱,快速排序的效率越体现的淋漓尽致。
- 实现步骤如下:
- 递归出口,条件为(low>high)
- 给指针i、j和基准值key赋值
- 完成一趟排序,循环条件为(i != j)
- 循环内部,
- 从右往左找小于等于key的值下标 j,条件为(a[j]>key)
- 从左往右找大于key的值下标 i,条件为(a[i]<=key&& i<j)
- 交换a[i]和a[j]的值
- 完成一趟循环之后,交换key和a[i]的位置
- 开始递归:
- 对key左边的数进行排序
- 对key右边的数进行排序
示例代码:
public static void quickSort(int[] a) {
if (a.length > 0) {
quickSort(a, 0, a.length - 1);
}
}
//核心递归体
private static void quickSort(int[] a, int low, int high) {
//递归出口
if (low > high) {
return;
}
int i = low;
int j = high;
int key = a[low]; //基准元素取第一个元素,取其他的直接改就行,28、29行也要改
//完成一趟排序
while (i != j) {//每当ij相等时跳出外层循环,每完成一趟遍历ij都是相等的;
while (a[j] > key) {//从右往左找到第一个小于等于key的数
j--;
}
while (a[i] <= key && i < j) {//从左往右找到第一个大于key的数,等于时也继续,i<j保证i不可能大于j
i++;
}
//交换两数字位置
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//调整key的位置,将key的位置与ij相遇的位置交换
int temp = a[i];
a[i] = a[low];
a[low] = temp;
//对key左边的数进行排序
quickSort(a, low, i - 1);
//对key右边的数进行排序
quickSort(a, i + 1, high);
}
复制代码