一、冒泡排序
从排列的第一个元素开始,比较与其右元素的大小关系,不符合排序要求则交换,如:从左到右正向排序,左大于右,则交换,但是排序比较的焦点始终加一地前进。这样一轮比较下来,最大的一定排到了最后(从第一个开始与后面的比较,遇到小的直接交换位置,遇到更大的则选择更大的,带着更大的往后比较),这样有多少数,就排序多少数-1轮,最后全部排序完
冒泡排序算法原理示例图
代码实例:
#include <stdio.h>
void bubblesort(int *a, int n)
{
for (int i = 0; i < n - 1; i++) //一共n个数,最坏情况进行n-1轮排序
{
int changed = 0,temp = 0; //记录一轮排序交换的次数,temp用于交换
for (int j = 0; j < n-1; j++)
{
if(a[j]>a[j+1])//前面比后面大,就交换
{
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
changed += 1;//交换次数+1
}
}
if(changed == 0)//如果有一轮没有发生交换,说明排序好了,提前结束
break;
}
}
int main()
{
int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
bubblesort(a, 10);
for (int i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
输出:
0 1 2 3 4 5 6 7 8 9
- 比较的循环最多进行n-1次,最坏的情况就是上面举例的这样,逆序的用冒泡排正序,这样时间复杂度就直接到最大 : O( n2),最好的情况当然就是已经排序好的,一遍排序就结束: O(n)。
- 在循环当中加入一个交换次数的比较,交换次数为0就表示排序完成,就停止整个循环,这样就提高了排序的效率
冒泡排序的比较次数:
每一轮的元素都要和其他未排序好的元素进行比较
第一轮的比较次数是n-1(n为个数),第二轮就不用再比较最后的最大数,依次为n-1,n-2,…1,共n(n-1)/2次
时间复杂度: O(n2) 空间复杂度 :O(1)
二,选择排序
排序原理:
- 在排序序列中找到最大(小)的数,与a[0]交换位置
- 在剩余序列中找到最大(小)的数,与a[1]交换位置
- …………
- 在剩余两数中找到最大(小)的数,与a[n-1]交换位置
选择排序算法原理示例图:
代码实例:
#include <stdio.h>
void select_sort(int *a, int n)
{
for (int i = 0; i < n; i++)//从0开始,一共进行n-1轮比较
{
int target = i; //用于记录已知排序好的元素的位置
for (int j = i + 1; j < n; j++)//从已知排序好的下一位出发
{
if (a[j] < a[target]) //找到未排序序列中的最小数
{
int temp = a[target];
a[target] = a[j];
a[j] = temp;
}
}
}
}
int main()
{
int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
select_sort(a, 10);
for (int i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
输出:
0 1 2 3 4 5 6 7 8 9
选择排序将排序序列分为了已排序好的部分与未排序好的部分,逐渐将未排序好部分中的数提出到排序好的部分。
由此:就可以有另一种双向选择排序的方式,一趟排序进行最大最小两个选择
代码实例:
#include <stdio.h>
void select_sort2(int *a, int n)
{
for (int i = 0, j = n - 1; i < j; i++, j--)
//i是一趟排序里面的第一个,j是一趟排序里面的最后一个
{
int min, max = i;//一开始就取一个作比较,不是这个也可以
for (int k = i; k <= j; k++)//找到剩余序列中的最大与最小下标
{
if (a[k] < a[min])//有更小就存一下下标
min = k;
if (a[k] > a[max])//有更大就存一下下标
max = k;
}
int temp = a[i];//交换最小
a[i] = a[min];
a[min] = temp;
if(i == max)//如果最大值刚好在最左,那么为了不重复交换
{
max = min;//刚才最小的位置就应该是真正最大的位置
}
int temp2 = a[j];//交换最大
a[j] = a[max];
a[max] = temp2;
}
}
int main()
{
int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
select_sort2(a, 10);
for (int i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
输出:
0 1 2 3 4 5 6 7 8 9
选择排序
时间复杂度: O(n2) 空间复杂度 :O(1)
三,插入排序
排序原理:
- 将排序序列分为了已排序好的部分与未排序好的部分,逐渐将未排序好部分中的数提出到排序好的部分
- 把序列中第一个元素作为排序好的第一个元素
- 把第二个元素插入到排序的区域中合适的位置
- 对后面的元素重复上一步骤
插入排序算法原理示例图
代码实例:
#include <stdio.h>
void insertSort(int *a, int n)
{
for (int i = 1; i < n; i++)
//因为把第一个当做已经排序好的,所以一共进行n-1轮
{
int temp = a[i];//未排序的第一个赋值给temp
int j = 0;//定义j=0
for (j = i - 1; j >= 0; j--)//开始循环比较
{
if (temp < a[j])
{
a[j + 1] = a[j];//第一轮:9换到了8的位置上,变成9976543210
}
else
{
break;
}
}
// printf("%d\n", j);
a[j + 1] = temp;//这时j=?
//第一轮:把提前存储的8换到了9上,变成,8976543210
for (int p = 0; p < 10; p++)//这里把每一轮的排序结果都输出一次
printf("%d ", a[p]);//看得到排序的过程
printf("\n");
}
}
int main()
{
int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
insertSort(a, 10);
// for (int i = 0; i < 10; i++)
// printf("%d ", a[i]);
printf("\n");
return 0;
}
输出:
8 9 7 6 5 4 3 2 1 0
7 8 9 6 5 4 3 2 1 0
6 7 8 9 5 4 3 2 1 0
5 6 7 8 9 4 3 2 1 0
4 5 6 7 8 9 3 2 1 0
3 4 5 6 7 8 9 2 1 0
2 3 4 5 6 7 8 9 1 0
1 2 3 4 5 6 7 8 9 0
0 1 2 3 4 5 6 7 8 9
插入排序
时间复杂度: O(n2) 空间复杂度 :O(1)
四,希尔排序
排序原理:
- 先将待排记录序列分割成为若干子序列分别进行插入排序,
- 待整个序列中的记录"基本有序"时,再对全体记录进行一次直接插入排序。
- 对一个“几乎”已经排好序的无序序列,插入排序的效率是很高的,可以达到线性排序的效率。比如,当序列中只有一位元素没有在适当的位置,那么整个序列只需要移动该序列的位置即可达到完成排序的任务。希尔排序就是利用这一点,进行了一个插入排序的升级
代码实例:
#include <stdio.h>
void shellSort(int *a, int n)
{
int length = n;//获取数组长度
int i, j, k;//定义变量
do//do-while循环(先做再判断)
{
length = length / 3 + 1;//保证至少有一轮
for (i = 0; i < length; i++)
//循环比较的组的次数,例如十个数,有四组比较,循环四组
{
for (j = i + length; j < n; j += length)
//同一组的进行比较排序
{
if (a[j] < a[j - length])
{
int temp = a[j];
for (k = j - length; k >= 0 && temp < a[k]; k -= length)//插入排序
{
a[k + length] = a[k];
}
a[k + length] = temp;
}
}
}
} while (length > 1);
}
int main()
{
int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
shellSort(a, 10);
for (int i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
运行结果:
0 1 2 3 4 5 6 7 8 9
希尔排序
时间复杂度: O(n2) 空间复杂度 :O(1)
希尔排序的效率依赖于递减增量序列的选择,时间复杂度最坏的情况是O(nlog2n)。
五、快速排序
排序原理:
- 通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。
- 一趟快速排序的具体过程可描述为:从待排序列中任意选取一个记录(通常选取第一个记录)作为基准值,然后将记录中关键字比它小的记录都安置在它的位置之前,将记录中关键字比它大的记录都安置在它的位置之后。这样,以该基准值为分界线,将待排序列分成的两个子序列。
代码实例:
#include <stdio.h>
void quickSort(int *a, int start, int end)
{
int i = start;
int j = end;
int baseval = a[start];
//(通常选取第一个记录)作为基准值
while (i < j)
{
while (i < j && a[j] >= baseval) // 从右向左找第一个小于x的数
{
j--;
}
if (i < j)
{
a[i++] = a[j];
}
while (i < j && a[i] < baseval) // 从左向右找第一个大于等于x的数
{
i++;
}
if (i < j)
{
a[j--] = a[i];
}
a[i] = baseval;
quickSort(a, start, i - 1);//递归
quickSort(a, i + 1, end);
}
}
int main()
{
int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
quickSort(a, 0, 9);
for (int i = 0; i < 10; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
运行结果:
0 1 2 3 4 5 6 7 8 9