各种排序算法(1)冒泡排序 选择排序 快速排序
1. 冒泡排序
1.1 名字由来:
算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序排列),
就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
1.2 冒泡思想
重复地遍历过要排序的数列,依次比较两个相邻的元素,如果他们的顺序错误就把他们交换过来(升序排列)。
把大(小)的元素往前(后)调
1.3 原理
- 从头到尾依次比较相邻的两个元素,如果第一个比第二个大,就交换两个位置;
- 第一次比较完,最后一个就是最大数
- 重复步骤1,除了最后一个数。
- 第二次比较完,最后第二个数就是次大数
1.4 时间复杂度:O(n^2)
最差是:O(n^2),在待排数据正好是反序的,需要进行n-1趟,每次比较n-i (1<=i<=n-1),复杂度是O((n-1)(n-i)),所以就是O(n^2)
最好是:O(1),在待排数据正好是正序的,一遍就可以排序完。复杂度是O(n)
因此冒泡排序总的平均时间复杂度为O(n^2)。
1.5 空间复杂度:1
1.6 是否稳定:稳定
1.7 代码例子
#include <stdio.h>
/* 交换两个值 */
void mySwap(int *i, int *j)
{
int iTmp = *i;
*i = *j;
*j = iTmp;
}
/* 打印 */
void myPrint(int arr[], int len)
{
for (int iLoop = 0; iLoop < len; iLoop++)
{
printf("%d ",arr[iLoop]);
}
printf("\n");
}
void bubble_sort(int arr[], int len)
{
/* 1. 注意这里i<len-1 n个数,最多进行n-1 次排序
如:10个数,比较9次即可 */
for (int i = 0; i < len-1; i++)
{
/* 2. 注意这里:j<len-i-1,就是后面(已经比较的)的不用进行比较了,
或者说 排序过程中,分为有序区和无序区*/
for (int j = 0; j < len - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
mySwap(&arr[j], &arr[j + 1]);
}
}
}
}
void test_bubble()
{
printf("test_bubble start \n");
int aiBubbleArr[] = {5, 8, 3, 14, 1 };
int arrLen = sizeof(aiBubbleArr)/sizeof(aiBubbleArr[0]);
myPrint(aiBubbleArr, arrLen);
bubble_sort(aiBubbleArr, arrLen);
myPrint(aiBubbleArr, arrLen);
printf("test_bubble end \n");
}
int main()
{
test_bubble();
return 0;
}
结果:
test_bubble start
5 8 3 14 1
1 3 5 8 14
test_bubble end
2. 选择排序
2.1 选择思想
每次选择最小(大)的元素放到开头(结尾)。
2.2 原理
- 从头到尾遍历找到最小的元素放到开始的位置
- 然后,再从未排序的找出最小的元素放到已排数的尾部
- 继续……直到所有元素均排序完毕
2.3 时间复杂度:O(n^2)
选择排序比冒泡排序快,因为交换次数比冒泡排序少多了。
2.4 空间复杂度:1
2.5 是否稳定:不稳定
序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
2.6 代码例子
#include <stdio.h>
/* 交换两个值 */
void mySwap(int *i, int *j)
{
int iTmp = *i;
*i = *j;
*j = iTmp;
}
/* 打印 */
void myPrint(int arr[], int len)
{
for (int iLoop = 0; iLoop < len; iLoop++)
{
printf("%d ",arr[iLoop]);
}
printf("\n");
}
void select_sort(int arr[], int len)
{
int iMinTmp = 0;
for(int i = 0; i < len -1; i++)
{
iMinTmp = i;
for(int j = i + 1; j < len; j++)
{
if(arr[iMinTmp] > arr[j])
{
iMinTmp = j;
}
}
if(iMinTmp != i)
{
mySwap(&arr[iMinTmp], &arr[i]);
}
}
}
void test_select()
{
printf("test_select start \n");
int aiselectArr[] = {5, 8, 3, 14, 1 };
int arrLen = sizeof(aiselectArr)/sizeof(aiselectArr[0]);
myPrint(aiselectArr, arrLen);
select_sort(aiselectArr, arrLen);
myPrint(aiselectArr, arrLen);
printf("test_select end \n");
}
int main()
{
test_select();
return 0;
}
3. 快速排序
3.1 快排
- 找出一个基准(如使用待排的第一个数),然后将数据分割成两个部分,一部分比基准都大,另外一部分比基准都小。然后递归。
- 快速排序(Quicksort)是对冒泡排序的一种改进
3.1.1 思想
快速排序思想----分治法
- 先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
3.1.2 效率
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用。
3.2 步骤
- 先找出一个基准(分界值),将数据分成左右两个部分(不符合就和冒泡一样的交换数据);
- 将大于或等于基准的数放到右边,将小于基准的数放到左边;
- 然后递归进行左右部分进行排序
3.3 时间复杂度:O(nlog(n))
平均: O(nlog(n))
最差:O(n^2)
最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。
这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。
3.4 空间复杂度:O(1)
3.5 是否稳定:不稳定
假设待排序数组: a = [ 1, 2, 2, 3, 4, 5, 6 ];
在快速排序的随机选择比较子(即pivot)阶段:
若选择a[2](即数组中的第二个2)为比较子,而把大于等于比较子的数均放置在大数数组中,则a[1](即数组中的第一个2)会到pivot的右边, 那么数组中的两个2非原序(这就是“不稳定”)。
若选择 a[1] 为比较子,而把小于等于比较子的数均放置在小数数组中,则数组中的两个 2 顺序也非原序 。
这就说明,quick sort是不稳定的。
参考: https://www.cnblogs.com/zhangguicheng/p/12906102.html
3.6 代码例子
#include <stdio.h>
/* 交换两个值 */
void mySwap(int *i, int *j)
{
int iTmp = *i;
*i = *j;
*j = iTmp;
}
/* 打印 */
void myPrint(int arr[], int len)
{
for (int iLoop = 0; iLoop < len; iLoop++)
{
printf("%d ",arr[iLoop]);
}
printf("\n");
}
int quick_sort_partion(int arr[], int low, int high)
{
int pivot = arr[low];
while(low < high)
{
while((low < high) && (arr[high] >= pivot))
{
high--;
}
mySwap(&arr[low], &arr[high]);
while((low < high) && (arr[low] <= pivot))
{
low++;
}
mySwap(&arr[low], &arr[high]);
}
return low;
}
void quick_sort_proc(int arr[], int low, int high)
{
if(low < high)
{
int pivot = quick_sort_partion(arr, low, high);
quick_sort_proc(arr, low, pivot - 1);
quick_sort_proc(arr, pivot + 1, high);
}
}
void quick_sort(int arr[], int len)
{
quick_sort_proc(arr, 0, len - 1);
}
void test_quick()
{
printf("test_quick start \n");
int aiQuickArr[] = {5, 8, 3, 14, 1 };
int arrLen = sizeof(aiQuickArr)/sizeof(aiQuickArr[0]);
myPrint(aiQuickArr, arrLen);
quick_sort(aiQuickArr, arrLen);
myPrint(aiQuickArr, arrLen);
printf("test_quick end \n");
}
int main()
{
test_quick();
return 0;
}