交换排序总结
前言:
1、分治法的基本思想
分治法的基本思想是将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解决这些子问题,然后将这些子问题的解组合为原问题的解。
2、交换排序的基本思想
1)交换排序的基本思想是两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。
2)应用交换排序基本思想的主要有冒泡排序和快速排序。
一、快速排序
1、快速排序的基本思想
设当前待排序的无序区为R[low…high],利用分治法可将快速排序的基本思想描述为:
1. 分解
在R[low…high]中任选一个记录作为基准(Pivot),以此基准将当前无序区划分为左、右两个较小的子区间R[low…pivotpos-1]和R[pivotpos+1…high],并使左边区间小于等于Pivot值,右边区间大于等于Pivot值,而Pivot位于正确的位置上即可。
2. 求解
通过递归调用快速排序对左、右区间快速排序。
3. 组合
因为当“求解”步骤中的两个递归调用结束时,其左右两个子区间已有序。对快速排序而言,“组合”步骤无须做什么,可看做是空操作。
2、快速排序算法的核心
- 区间划分:将基准值放在正确的位置上,使其左边区间值<=基准值<=右边区间值;返回基准位置值。
- 递归调用:在区间条件下,对[最左边位置 基准位置-1]和[基准位置+1 最右边位置]的元素进行递归调用。
3、快速排序算法的实现
/**
目的:
1、将基准值放在正确的位置上
2、将基准值的位置返回
思路:
1、将序列第一个值假设为基准值
2、对整个序列比较,查找基准值位置
从高位置开始:
1)忽略大于或等于基准值位置上的值
2)保存小于基准值的值
从低位置开始:
1)忽略小于或等于基准值位置上的值
2)保存大于于基准值的值
3、将基准值放在正确位置上,并返回这个正确位置。
*/
int Partition(int *arr, int low, int high)
{
int pivot; // 记录基准值
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;
}
/**
思路:
1、在条件下,保证递归正确执行
2、得到分区的位置
3、对左右两个区域进行递归调用
*/
void QuickSort(int *arr, int low, int high)
{
if (low<high)
{
// 获取基准值的位置
int pos = Partition(arr,low,high);
// 对左右区间进行递归调用
QuickSort(arr,low,pos-1);
QuickSort(arr,pos+1,high);
}
}
4、时间复杂度
快速排序法是一种不稳定的排序方法,平均时间复杂度O(nlogn),最差情况时间复杂度为O(n^2)。
二、冒泡排序
冒泡排序法是一个比较简单的排序方法。在待排序的序列基本有序的情况下排序速度较快。
冒泡排序就是把小的元素往前调或者把大的元素往后调。
假设排序的数有n个,则需要n-1轮排序,第i轮排序中,相邻两元素相比较比较,如不符合条件,就交换其值。
1、算法核心
- 确定外循环的次数(n-1)
- 内循环起始位置
- 相邻元素比较 (其目的将大的元素往后调)
2、算法实现
1)最简单版本
void Bubble(int *arr,int len)
{
int i,j;
for (i=0; i<len-1; i++) // len个数,需要针对len-1个数进行排序
{
for (j=0;j<len-i-1;j++) // 确定内循环起始位置
{
if (arr[j+1]<arr[j]) // 相邻元素的比较
{
arr[j+1] = arr[j+1]^arr[j];
arr[j] = arr[j+1]^arr[j];
arr[j+1] = arr[j+1]^arr[j];
}
}
}
}
2)加强版
void Bubble(int *arr,int len)
{
int i,j;
bool exchange;
for (i=0; i<len-1; i++) // len个数,需要针对len-1个数进行排序
{
exchange = false; // 设置交换标记
for (j=0;j<len-i-1;j++) // 确定内循环起始位置
{
if (arr[j+1]<arr[j]) // 相邻元素的比较
{
arr[j+1] = arr[j+1]^arr[j];
arr[j] = arr[j+1]^arr[j];
arr[j+1] = arr[j+1]^arr[j];
exchange = true;
}
}
if (!exchange)
{
return;
}
}
}
3、时间复杂度
冒泡排序是就地排序,且它是稳定的。冒泡排序最好时间复杂度为O(n),最坏时间复杂度为O(n^2),平均时间复杂度为O(n^2)。