冒泡排序(交换)
比较并交换相邻元素,每轮比较获得一个最值,最值沉底,下一轮在其余元素之间比较,同样获得一个最值并沉底(此值应比上一轮得到的最值小),循环此过程,所需比较的元素逐渐减少
#include<stdio.h>
void BubbleSort(int* num, int len);
int main(void) {
int num[12]={ 2,5,4,9,6,1,3,11,36,21,66,15 };
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("原始数据\n");
BubbleSort(num, 12);
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("结果");
return 0;
}
void BubbleSort(int *num, int size) {
int m;
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (num[j] > num[j + 1]) {
m = num[j];
num[j] = num[j + 1];
num[j + 1] = m;
}
}
for (int n = 0; n < 12; n++) {
printf("%d ", num[n]);
}
printf("第%d轮\n",i+1);
}
}
输出:
2 5 4 9 6 1 3 11 36 21 66 15 原始数据
2 4 5 6 1 3 9 11 21 36 15 66 第1轮
2 4 5 1 3 6 9 11 21 15 36 66 第2轮
2 4 1 3 5 6 9 11 15 21 36 66 第3轮
2 1 3 4 5 6 9 11 15 21 36 66 第4轮
1 2 3 4 5 6 9 11 15 21 36 66 第5轮 //从此处开始多余排序,可优化
1 2 3 4 5 6 9 11 15 21 36 66 第6轮
1 2 3 4 5 6 9 11 15 21 36 66 第7轮
1 2 3 4 5 6 9 11 15 21 36 66 第8轮
1 2 3 4 5 6 9 11 15 21 36 66 第9轮
1 2 3 4 5 6 9 11 15 21 36 66 第10轮
1 2 3 4 5 6 9 11 15 21 36 66 第11轮
1 2 3 4 5 6 9 11 15 21 36 66 结果
优化冒泡算法:
void BubbleSort(int *num, int size) {
int m,p=0;
for (int i = 0; i < size - 1; i++) {
p = 0; //设置标记点
for (int j = 0; j < size - i - 1; j++) {
if (num[j] > num[j + 1]) {
m = num[j];
num[j] = num[j + 1];
num[j + 1] = m;
p=1; //若标记点变化意味着排序未完成
}
}
if (p != 1) //若标记点未变化意味着排序已完成,可以结束排序
break;
for (int n = 0; n < 12; n++) {
printf("%d ", num[n]);
}
printf("第%d轮\n",i+1);
}
}
优化后的输出:
2 5 4 9 6 1 3 11 36 21 66 15 原始数据
2 4 5 6 1 3 9 11 21 36 15 66 第1轮
2 4 5 1 3 6 9 11 21 15 36 66 第2轮
2 4 1 3 5 6 9 11 15 21 36 66 第3轮
2 1 3 4 5 6 9 11 15 21 36 66 第4轮
1 2 3 4 5 6 9 11 15 21 36 66 第5轮
1 2 3 4 5 6 9 11 15 21 36 66 结果
外层循环体循环比较轮数,内层循环体循环相邻元素间比较次数(随i递减)
waronig:
函数第一个参数需要声明为指针
快速排序(交换)
快速排序是目前所有内部排序算法中平均性能最优的排序算法。
快速排序的基本思想:通过一轮排序将待排数据分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
选择排序的基本思想:比较 + 交换。
在待排序记录r1 到 r[n]中选出最小的记录,将它与r1交换;
在待排序记录r2 到 r[n]中选出最小的记录,将它与r2交换;
在待排序记录ri 到 r[n]中选出最小的记录,将它与r[i]交换,使有序序列不断增长直到全部排序完毕。
直接插入排序(插入)
将待排序的无序数列看成是一个仅含有一个元素的有序数列和一个无序数列,将无序数列中的元素逐次插入到有序数列中,从而获得最终的有序数列。
- 从第一个元素开始,该元素可以认为已经被排序;
- 取出下一个元素,在已经排序的元素序列中从后向前扫描;
- 如果该元素(已排序)大于新元素,将该元素移到下一位置;
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
- 将新元素插入到该位置后;
重复步骤2~5。
#include<stdio.h>
void InsertionSort(int* num, int len);
int main(void) {
int num[12]={ 2,5,4,9,6,1,3,11,36,21,66,15 };
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("原始数据\n");
InsertionSort(num, 12);
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("结果");
return 0;
}
void InsertionSort(int* num, int len) {
int i, j;
for (i = 1; i < len; i++) { //外层循环轮数
if (num[i] < num[i - 1]) { //将前一个元素与后一个比较,若为真
int temp = num[i]; //临时储存后一个元素,num[i]为待插入元素,应与前一个元素比较,所以初始为数组第二个元素
//第一次排序后的前两个元素有序,第2,3个无序;
//当此时在第二轮时num[i]为第三个元素,将与第1,2个元素比较,找到位置后插入(下一组循环)
for (j = i - 1; j >= 0 && num[j] > temp; j--) { //第一个j为后一个元素(待插入元素)后一个元素会与前面所有元素相比较
//循环条件2为后一个元素大于前一个元素,若未找到,j--,会与前面所有元素比较
//每一个num[i]与前一个比较(寻找插入位置)
num[j + 1] = num[j]; //将比较后的元素后移(将前一个位置上的元素赋值给后一个位置上的元素)
}
num[j + 1] = temp; //复制到插入的位置(num[j+1]作为一个标,下标为待插入的位置)因为[j+1]在不断变化
///
//因为元素后移,切不可将for中的temp改为num[i] //
///
}
for (int n = 0; n < 12; n++) {
printf("%d ", num[n]);
}
printf("第%d轮\n", i );
}
}
2 5 4 9 6 1 3 11 36 21 66 15 原始数据
2 5 4 9 6 1 3 11 36 21 66 15 第1轮
2 4 5 9 6 1 3 11 36 21 66 15 第2轮
2 4 5 9 6 1 3 11 36 21 66 15 第3轮
2 4 5 6 9 1 3 11 36 21 66 15 第4轮
1 2 4 5 6 9 3 11 36 21 66 15 第5轮
1 2 3 4 5 6 9 11 36 21 66 15 第6轮
1 2 3 4 5 6 9 11 36 21 66 15 第7轮
1 2 3 4 5 6 9 11 36 21 66 15 第8轮
1 2 3 4 5 6 9 11 21 36 66 15 第9轮
1 2 3 4 5 6 9 11 21 36 66 15 第10轮
1 2 3 4 5 6 9 11 15 21 36 66 第11轮
1 2 3 4 5 6 9 11 15 21 36 66 结果
//直接插入法二:用数据交换代替法一的数据后移(比较对象只考虑两个元素)
void InsertSort2(int*num, int len)
{
for (int i = 1; i < len; i++)
for (int j = i - 1; j >= 0 && num[j] > num[j + 1]; j--)
Swap(num[j], num[j + 1]);
}
void Swap(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
}
希尔排序(插入)
是简单插入排序的改进版,它与插入排序的不同之处在于它会优先比较距离较远的元素。
希尔排序又叫缩小增量排序。
希尔排序时效分析很难,关键码的比较次数与记录移动次数依赖于增量因子序列d的选取,特定情况下可以准确估算出关键码的比较次数和记录的移动次数。目前还没有人给出选取最好的 增量因子序列的方法。 增量因子序列可以有各种取法,有取奇数的,也有取质数的,但需要注意: 增量因子中除1 外没有公因子,且最后一个 增量因子必须为1。希尔排序方法是一个不稳定的排序方法。
- 先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列。
- 每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。
- 继续不断缩小增量直至为1,最后使用直接插入排序完成排序。
#include<stdio.h>
void ShellSort(int* arr, int size);
int main(void) {
int num[12]={ 2,5,4,9,6,1,3,11,36,21,66,15 };
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("原始数据\n");
ShellSort(num, 12);
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("结果");
return 0;
}
void ShellSort(int* arr, int size)
{
int i, j, tmp, increment;
for (increment = size / 2; increment > 0; increment /= 2) { //选择一个增量序列,个数为k,进行k轮排序
for (i = increment; i < size; i++) { //增量决定轮数 此时增量为常量
tmp = arr[i];
for (j = i - increment; j >= 0 && tmp < arr[j]; j -= increment) { //j=j-increment(增量);
arr[j + increment] = arr[j];
}
arr[j + increment] = tmp;
for (int n = 0; n < 12; n++) {
printf("%d ", arr[n]);
}
printf("第%d轮\n", i );
}
}
}
输出:
2 5 4 9 6 1 3 11 36 21 66 15 原始数据
2 5 4 9 6 1 3 11 36 21 66 15 第6轮
2 5 4 9 6 1 3 11 36 21 66 15 第7轮
2 5 4 9 6 1 3 11 36 21 66 15 第8轮
2 5 4 9 6 1 3 11 36 21 66 15 第9轮
2 5 4 9 6 1 3 11 36 21 66 15 第10轮
2 5 4 9 6 1 3 11 36 21 66 15 第11轮
2 5 4 9 6 1 3 11 36 21 66 15 第3轮
2 5 4 9 6 1 3 11 36 21 66 15 第4轮
2 5 1 9 6 4 3 11 36 21 66 15 第5轮
2 5 1 3 6 4 9 11 36 21 66 15 第6轮
2 5 1 3 6 4 9 11 36 21 66 15 第7轮
2 5 1 3 6 4 9 11 36 21 66 15 第8轮
2 5 1 3 6 4 9 11 36 21 66 15 第9轮
2 5 1 3 6 4 9 11 36 21 66 15 第10轮
2 5 1 3 6 4 9 11 15 21 66 36 第11轮
2 5 1 3 6 4 9 11 15 21 66 36 第1轮
1 2 5 3 6 4 9 11 15 21 66 36 第2轮
1 2 3 5 6 4 9 11 15 21 66 36 第3轮
1 2 3 5 6 4 9 11 15 21 66 36 第4轮
1 2 3 4 5 6 9 11 15 21 66 36 第5轮
1 2 3 4 5 6 9 11 15 21 66 36 第6轮
1 2 3 4 5 6 9 11 15 21 66 36 第7轮
1 2 3 4 5 6 9 11 15 21 66 36 第8轮
1 2 3 4 5 6 9 11 15 21 66 36 第9轮
1 2 3 4 5 6 9 11 15 21 66 36 第10轮
1 2 3 4 5 6 9 11 15 21 36 66 第11轮
1 2 3 4 5 6 9 11 15 21 36 66 结果
简单选择排序(选择)
在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
#include<stdio.h>
void SelectSort(int a[], int n);
int main(void) {
int num[12]={ 2,5,4,9,6,1,3,11,36,21,66,15 };
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("原始数据\n");
SelectSort(num, 12);
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("结果");
return 0;
}
void SelectSort(int *a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int k = i; //记录最小值
for (int j = i + 1; j < n; j++) //遍历找到最小值
if (a[j] < a[k]) //从下一个元素开始若有元素小于纪录的最小值k,则交换最小值(k的值)
k = j;
if (k != i) //交换a[i]与a[k]的值 (将最小值赋值给原数组第一个元素)
{
int t = a[i];
a[i] = a[k];
a[k] = t;
}
for (int n = 0; n < 12; n++) {
printf("%d ", a[n]);
}
printf("第%d轮\n", i+1);
}
}
输出:
2 5 4 9 6 1 3 11 36 21 66 15 原始数据
1 5 4 9 6 2 3 11 36 21 66 15 第1轮
1 2 4 9 6 5 3 11 36 21 66 15 第2轮
1 2 3 9 6 5 4 11 36 21 66 15 第3轮
1 2 3 4 6 5 9 11 36 21 66 15 第4轮
1 2 3 4 5 6 9 11 36 21 66 15 第5轮
1 2 3 4 5 6 9 11 36 21 66 15 第6轮
1 2 3 4 5 6 9 11 36 21 66 15 第7轮
1 2 3 4 5 6 9 11 36 21 66 15 第8轮
1 2 3 4 5 6 9 11 15 21 66 36 第9轮
1 2 3 4 5 6 9 11 15 21 66 36 第10轮
1 2 3 4 5 6 9 11 15 21 36 66 第11轮
1 2 3 4 5 6 9 11 15 21 36 66 结果
待补(…)
总述(可直接复制调用的排序函数)
//冒泡
void BubbleSort(int *num, int size) {
int m;
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < size - i - 1; j++) {
if (num[j] > num[j + 1]) {
m = num[j];
num[j] = num[j + 1];
num[j + 1] = m;
}
}
}
//直接插入
void InsertionSort(int* num, int len) {
int i, j;
for (i = 1; i < len; i++) {
if (num[i] < num[i - 1]) {
int temp = num[i];
for (j = i - 1; j >= 0 && num[j] > temp; j--) {
num[j + 1] = num[j];
}
num[j + 1] = temp;
}
}
}
//简单选择
void SelectSort(int *a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int k = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[k])
k = j;
if (k != i)
{
int t = a[i];
a[i] = a[k];
a[k] = t;
}
}
}
//qsort的使用
#include<stdlib.h>
int comp(const* a, const* b) { //比较函数
return *(int*)a - *(int*)b; //默认从小到大排序,如需从大到小,令:
//*(int*)b - *(int*)a
}
qsort(num, 12,sizeof(int),comp); //s1:待排序列 s2:待排序列大小
//s3:待排类型 s4: 自定义函数
c标准库函数
qsort:
qsort函数(全称quicksort)。它是ANSI C标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,其时间复杂度为nlog(n)
void qsort(void base,size_t num,size_t width,int(__cdeclcompare)(const void,const void*));
参数:
-
待排序数组,排序之后的结果仍放在这个数组中
-
数组中待排序元素数量
-
各元素的占用空间大小(单位为字节)
-
指向函数的指针,用于确定排序的顺序(需要用户自定义一个比较函数)
qsort要求提供一个自己定义的比较函数。比较函数使得qsort通用性更好,有了比较函数qsort可以实现对数组、字符串、结构体等结构进行升序或降序排序。
如比较函数 int cmp(const void *a, const void *b) 中有两个元素作为参数(参数的格式不能变),返回一个int值,比较函数cmp的作用就是给qsort指明元素的大小是怎么比较的。
代码示例
#include<stdio.h>
#include<stdlib.h>
int comp(const* a, const* b) {
return *(int*)a - *(int*)b; //默认从小到大排序,如需从大到小,令:
//*(int*)b - *(int*)a
}
int main(void) {
int num[12]={ 2,5,4,9,6,1,3,11,36,21,66,15 };
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("原始数据\n");
qsort(num, 12,sizeof(int),comp);
for (int i = 0; i < 12; i++)
printf("%d ", num[i]);
printf("结果");
return 0;
}