一.排序算法概述
十种排序算法可以分为两类:
- 比较类的排序:通过比较来决定元素间的相对次序,时间复杂度不能突破O(nlogn),又被称为非线性时间比较类排序
- 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此又被称为线性时间非比较类排序。
上面的文字与图来自[ 十大经典排序算法(动图演示)](www.cnblogs.com/onepixel/ar…)
1.1 时间复杂度
二.冒泡排序
2.1 思想
从前往后比较相邻元素,如果排序要求从小到大,则将大的数往后排,直到将最大的数排到最后
上图中有6个元素,需要比较5趟就结束了,每一趟比较的次数为数据长度-比较的趟数-1
2.2 算法步骤
- 比较相邻两个元素,如果逆序则交换他们
- 每一对相邻的元素都做这样的操作,比较完成之后最大的元素会是最后一个
- 最好的情况是序列中元素都为正序,只需要比较n-1次,最坏的情况是序列中的元素都为逆序
- 稳定排序
void bubbleSort(int a[],int len)
{
int i = 0;
int j = 0;
int temp;
for (i = 0; i < len - 1; i++)
{
for (j = 0; j < len -1 -i; j++)//排了一趟之后最后一个数为最大值,就不需要排序了
{
if (a[j + 1] < a[j])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
复制代码
代码优化,如果某一趟排序没有发生交换,则说明这趟排序已经将数据顺序排序好,不需要进行下一次排序,增加一个标志位即可
void bubbleSort2(int a[], int len)
{
int i = 0;
int j = 0;
int temp;
bool flag = false;
for (i = 0; i < len - 1; i++)
{
for (j = 0; j < len - 1 - i; j++)//排了一趟之后最后一个数为最大值,就不需要排序了
{
if (a[j + 1] < a[j])
{
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
flag = true;
}
}
if (!flag)//比较某趟完成之后判断flag是否为flase,表示没有发生交换
{
break;//如果某一次排序时没有发生交换,提前结束排序
}
}
}
复制代码
三.快速排序
3.1 思想
- 从要排序的数据中选择一个基准数
- 通过一趟排序将比基准数小的数据排左边,比基准数大的数据排右边
- 再通过步骤2将中的两个部分进行排序,排序过程递归进行,最后整个数据变成有序序列
想可以概括为:挖坑填数 + 分治法
3.2 分治法
分治:分而治之,通过将一个复杂的问题分为多个子问题,再把子问题分割成多个相似的更小的问题,直到最后子问题可以简单的直接求解,原问题的解就是多个子问题解的合并
3.3 例子
下面通过一个例子来看一下快速排序是怎么工作的,以第一个元素为基准数,红框框住的的位置表示需要填的坑,绿色框住的元素表示已经移动赋值过的元素
- 开始时:i和j分别指向需要排序的数组的头部和尾部,i = 0,j = 7,取基准数为左边的数,base = array[0] = array[i] = 20,这时候从后往左边开始找,即从j=7的位置开始往左边,每一次移动j都要减1,当j = 6时,符合条件,此时将array[6]的值直接填充到array[0]处,并且将i向右边移动一个位置,即i++.
伪代码为:
while (left < right && array[right] >= base)//从右往左寻找到一个比基准数小的值
{
right--;
}
//找到了比基准数小的值,直接填充到left所在的位置
if (left < right)
{
array[left] = array[right];
left++; //left的下标加1,即往右移动
}
复制代码
此时图为
- 这时array[0]的坑被array[6]给填充了,array[6]的所在的地方又重新成了一个坑,此时从左往右开始寻找一个大于base值的数填充到array[6]的地方,于是将array[1]赋值为给array[6],同时将j往左边移动一个位置,即j--
代码为:
while (left < right && array[left] < base)//从左往右寻找到一个比基准数大的值
{
left++;
}
//找到了比基准数大的值,直接填充到rigth所在的位置
if (left < right)
{
array[right] = array[left];
right--; //right的下标加1,即往左移动
}
复制代码
此时图为:
- 最后图示为
接着只需要对array[5]两边的元素进行操作即可
分治的代码为:
quickSort(array,left,left - 1);
quickSort(array,left + 1,right);
复制代码
3.4 代码为
void quickSort(int array[], int low, int high)
{
if (low >= high)
{
return;
}
int left = low;
int right = high;
int base = array[left];
while (left < right)
{
while (left < right && array[right] >= base)//从右往左寻找到一个比基准数小的值
{
right--;
}
//找到了比基准数小的值,直接填充到left所在的位置
if (left < right)
{
array[left] = array[right];
left++; //left的下标加1,即往右移动
}
while (left < right && array[left] < base)//从左往右寻找到一个比基准数大的值
{
left++;
}
//找到了比基准数大的值,直接填充到rigth所在的位置
if (left < right)
{
array[right] = array[left];
right--; //right的下标减1,即往左移动
}
array[left] = base;//将基准数填入最后的坑
quickSort(array, low, left - 1);
quickSort(array, left + 1, high);
}
}
复制代码