交换排序
利用交换元素的位置进行排序的方法称作交换排序
交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
常用的交换排序的方法:冒泡排序和快速排序
冒泡排序
冒泡排序原理:冒泡排序其实就是从头开始对整个数列里面的元素进行两两对比,比较大的元素放到后面,接着进行对比,直到最大的一个元素被提取出来放到整个数列的最后。接着再对剩下的元素进行相同的操作,直到整个数列被排序完成。
代码实现:
void Swap(int* x1, int* x2)
{
int tmp = *x1;
*x1 = *x2;
*x2 = tmp;
}
void BubbleSort(int* a, int n)
{
assert(a);
int end = n;
while (end > 0)
{
for (int i = 1; i < end; ++i)
{
if (a[i] < a[i - 1])
{
Swap(&a[i], &a[i - 1]);
}
}
end--;
}
}
void PrintArray(int* a, int n)
{
for (int i = 0; i < n; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
int main()
{
int a[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
BubbleSort(a, sizeof(a) / sizeof(a[0]));
PrintArray(a, sizeof(a) / sizeof(a[0]));
return 0;
}
运行结果如下:
冒泡排序的特性总结:
- 冒泡排序是一种非常容易理解的排序
- 时间复杂度:O(N^2)
- 空间复杂度:O(1)
- 稳定性:稳定
快速排序
快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法。
基本思想:
任取待排序元素序列中的某元素作为基准值,按照排序码将待排序集合分割成两个子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
将区间按照基准值划分为左右两半部分的常见方式有:
1.hoare版本
2.挖坑法
3.前后指针版本
代码实现:
下面三种方法都可以实现快速排序。
void Swap(int* x1, int* x2)
{
int tmp = *x1;
*x1 = *x2;
*x2 = tmp;
}
//方法一
int PartSort1(int* a, int begin, int end)
{
assert(a);
int key = a[end];
int keyindex = end;
while (begin < end)
{
//找大的
while (begin < end&&a[begin] <= key)
{
++begin;
}
//找小的
while (begin < end&&a[end] >= key)
{
--end;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[keyindex]);
return begin;
}
//方法二
int PartSort2(int* a, int begin, int end)
{
assert(a);
int key = a[end];
while (begin < end)
{
while (begin < end&&a[begin] <= key)
{
++begin;
}
a[end] = a[begin];
while (begin < end&&a[end] >= key)
{
--end;
}
a[begin] = a[end];
}
a[begin] = key;
return begin;
}
//方法三
int PartSort3(int* a, int begin, int end)
{
int prev = begin - 1;
int cur = begin;
int key = a[end];
while (cur < end)
{
if (a[cur] < key && ++prev != cur)
{
Swap(&a[cur], &a[prev]);
}
++cur;
}
Swap(&a[++prev], &a[end]);
return prev;
}
void QuickSort(int* a, int left, int right)
{
assert(a);
if (left >= right)
{
return;
}
int div = PartSort3(a, left, right);
//[left,div-1] div [div+1,right]
QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}
void PrintArray(int* a, int n)
{
for (int i = 0; i < n; ++i)
{
printf("%d ", a[i]);
}
printf("\n");
}
int main()
{
int a[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
QuickSort(a, 0, sizeof(a) / sizeof(a[0]) - 1);
PrintArray(a, sizeof(a) / sizeof(a[0]));
return 0;
}
运行结果如下:
快速排序的特性总结:
- 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
- 时间复杂度:O(N*logN)
- 空间复杂度:O(logN)
- 稳定性:不稳定