**基本思想:**所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排
序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
1、冒泡排序
它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
假设有一个大小为 N 的无序序列。以升序冒泡排序为例,冒泡排序就是要每趟排序过程中通过两两比较相邻元素,将小的数字放到前面,大的数字放在后面。每一趟排序都是为了得到一个最大的值,总共需要N趟,第i趟要比较的次数为N-i。
算法改进:加入标志性变量flag,用于标志某一趟排序过程中是否有数据交换。如果进行某一趟排序时并没有进行数据交换,则说明所有数据已经有序,可立即结束排序,避免不必要的比较过程。
// 冒泡排序--普通版
void BubbleSort(int arr[], int n)
{
int i, j;
for (i = 0; i < n; ++i)
{
for (j = 0; j < n - i - 1; ++j)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
}
}
}
}
// 冒泡排序--优化版
void BubbleSort_1(int arr[], int n)
{
int i, j;
for (i = 0; i < n; ++i)
{
int flag = 0;
for (j = 0; j < n - i - 1; ++j)
{
if (arr[j] > arr[j + 1])
{
flag = 1;
int tmp = arr[j + 1];
arr[j + 1] = arr[j];
arr[j] = tmp;
}
}
if (flag == 0)
break; //说明没有发生交换,说明已是有序
}
}
冒泡排序的特性总结:
- 冒泡排序是一种非常容易理解的排序
- 时间复杂度:O(N^2)
- 空间复杂度:O(1)
- 稳定性:稳定(相同数据不发生交换)
2、快速排序
基本思想:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
// 快速排序--挖坑法
int QSort(int arr[], int first, int last)
{
int end = last - 1;
int key = arr[first]; //设置第一个元素为关键字
while (first < end)
{
//先从后往前比较
while (first < end && key <= arr[end])
--end;
arr[first] = arr[end];
//比关键字小了之后,再从前往后比较
while (first < end && key >= arr[first])
++first;
arr[end] = arr[first];
}
//填坑
arr[first] = key;
//此时保证了key前面的序列都比key小,key后面的序列都比key大
return first; //返回坑的位置
}
void QuickSort(int arr[], int first, int last)
{
int mid;
if (first >= last - 1) //递归结束条件
return;
mid = QSort(arr, first, last);
QuickSort(arr, first, mid); //排序前面子序列
QuickSort(arr, mid + 1, last); //排序后面子序列
}
快速排序的特性总结:
- 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
- 时间复杂度:O(N*logN)
- 空间复杂度:O(logN)
- 稳定性:不稳定