七、数组排序算法
选择排序
每次选择所要排序数组中最大值(从小到大排序,则选择最小值)的数组元素,将这个数组元素的值与最前面没有进行排序的数组元素的值互换。
#include <stdio.h>
/*选择排序*/
int main() {
int i, j;
int a[10]; /* 用于存储输入的数字 */
int temp; /* 临时变量 */
int pos; /* 用于存储最大元素的下标 */
printf("为数组元素赋值:\n");
for (int i = 0; i < 10; i++) {
printf("a[%d]=", i);
scanf("%d", &a[i]); /* 从标准输入读取数组元素 */
}
/* 从大到小排序 */
for (int i = 0; i < 9; i++) { /* 外层循环,从第一个元素到倒数第二个元素 */
temp = a[i]; /* 将当前位置的元素作为临时最大值 */
pos = i; /* 记录当前最大值的下标 */
for (j = i + 1; j < 10; j++) { /* 内层循环,从当前位置的下一个元素开始到最后一个元素 */
if (a[j] > temp) { /* 如果找到比当前最大值更大的元素 */
temp = a[j]; /* 更新临时最大值 */
pos = j; /* 更新最大值的下标 */
}
}
/* 将找到的最大值放到当前位置 */
if (pos != i) { /* 只有当找到的最大值不是当前位置时才交换 */
a[pos] = a[i];
a[i] = temp;
}
}
/* 输出排序后的数组 */
for (int i = 0; i < 10; i++) {
printf("%d\t", a[i]);
if ((i + 1) % 5 == 0) { /* 当输出到每行的第五个元素时换行 */
printf("\n");
}
}
return 0;
}
初始数组资源 9 6 15 4 2 2和9对调
第一次排序后 2 6 15 4 9 4和6对调
第二次排序后 2 4 15 6 9 15和6对调
第三次排序后 2 4 6 15 9 15和9对调
第四次排序后 2 4 6 9 15
冒泡排序
排序时,每次比较数组中相邻的两个数组元素的值,将较小的数排在较大的数前面(从小到大排列)
#include <stdio.h>
/* 冒泡排序 */
int main() {
int i, j;
int a[10]; // 声明一个包含10个整数的数组
int temp; // 用于交换元素的临时变量
printf("为数组元素赋值:\n");
/* 通过键盘为数组元素赋值 */
for (int k = 0; k < 10; k++) {
printf("a[%d]=", k); // 提示用户输入每个数组元素的值
scanf("%d", &a[k]); // 将用户输入的值存入数组对应位置
}
/* 冒泡排序算法,从小到大排序 */
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9 - i; j++) {// 对当前未排序部分进行相邻元素比较,并交换位置,确保较大的元素逐步向右移动。
if (a[j] > a[j + 1]) { // 如果前一个元素大于后一个元素
temp = a[j]; // 交换两个元素
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
/* 输出排序后的数组 */
for (int k = 0; k < 10; k++) {
printf("%d\t", a[k]); // 按顺序输出数组中的元素
if (k == 4) {
printf("\n"); // 在第5个元素后换行,便于显示
}
}
return 0; // 返回0表示程序成功运行结束
}
初始数组资源 9 6 15 4 2
第一次排序后 2 【9 6 15 4】
第二次排序后 2 4 【9 6 15】
第三次排序后 2 4 6 【9 15】
第四次排序后 2 4 6 9 15
交换排序
交换排序是将每一位数与其后所有的数一一比较,如果发现符合条件的数据,则交换数据
#include <stdio.h>
/*交换排序*/
int main() {
int i, j;
int a[10];
int temp;
printf("为数组元素赋值:\n");
/* 通过键盘为数组元素赋值 */
for (int k = 0; k < 10; k++) {
printf("a[%d]=", k); // 提示用户输入每个数组元素的值
scanf("%d", &a[k]); // 将用户输入的值存入数组对应位置
}
/* 交换排序算法,从小到大排序 */
for (int i = 0; i < 9; i++) {
for (int j = i + 1; j < 10; j++) {
if (a[i] > a[j]) {
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
/* 输出排序后的数组 */
for (int k = 0; k < 10; k++) {
printf("%d\t", a[k]); // 按顺序输出数组中的元素
if (k == 4) {
printf("\n"); // 在第5个元素后换行,便于显示
}
}
return 0; // 返回0表示程序成功运行结束
}
初始数组资源 【9 6 15 4 2】
第一个数字9和6比较,9大于6,交换9和6;6 9 15 4 2
6再和15比较,保持原来位置;6 9 15 4 2
6再和4比较,6大于4,交换6和4;4 9 15 6 2
4再和2比较,4大于2,交换4和2;2 9 15 6 4
第一次排序后 2 【9 15 6 4】
第一个数字9和15比较,保持原来位置;2 9 15 6 4
9和6比较,9大于6,交换9和6;2 6 15 9 4
6和4比较,6大于4,交换6和4;2 4 15 9 6
第二次排序后 2 4 【15 9 6】
第一个数字15和9比较,15大于9,交换15和9;2 4 9 15 6
9和6比较,9大于6,交换9和6;2 4 6 15 9
第三次排序后 2 4 6 【15 9】
第一个数字15和9比较,15大于9,交换15和9;2 4 9 6 15
第四次排序后 2 4 6 9 15
插入排序
工作原理是抽出一个数据,在前面的数据中寻找相应的位置插入,直到完成排序。
将第一个数字取出来,并放置在第一个位置;
然后取出第二个数据,与第一个数据比较。
如果第二个数字小于第一个数字,则将第二个数字排在第一个数字之前;
否则就将第二个数字排在第一个数字之后;
接着取出下一个数字,先与排在后面的数字进行比较。
如果当前数字比较大,则排到最后面;
如果当前数字比较小,则还要与之前的数字进行比较,将当前数字排在比他小的数字和比他大的数字之间。
如果没有比当前数字小的数字,则将当前数字排到最前面;
#include <stdio.h>
/*插入排序*/
int main() {
int i, j;
int a[10]; // 声明一个包含10个整数的数组
int key; // 用于插入元素数据
printf("为数组元素赋值:\n");
/* 通过键盘为数组元素赋值 */
for (int k = 0; k < 10; k++) {
printf("a[%d]=", k); // 提示用户输入每个数组元素的值
scanf("%d", &a[k]); // 将用户输入的值存入数组对应位置
}
/*插入排序,从小到大*/
for (i = 1; i < 10; i++) {
key = a[i]; // 当前要插入的元素
j = i - 1;
// 将比 key 大的元素都向后移动
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = key; // 插入 key 到正确位置
}
/* 输出排序后的数组 */
for (int k = 0; k < 10; k++) {
printf("%d\t", a[k]); // 按顺序输出数组中的元素
if (k == 4) {
printf("\n"); // 在第5个元素后换行,便于显示
}
}
return 0; // 返回0表示程序成功运行结束
}
初始数组资源 9 6 15 4 2
第一次排序后 9
第二次排序后 6 9
第三次排序后 6 9 15
第四次排序后 4 6 9 15
第四次排序后 2 4 6 9 15
折半排序
又称快速排序,二分法,工作原理是先选择一个中间值middle(在程序中使用数组中间值),然后把比中间值小的数据放在左边,把比中间值大的放在右边,最后对两边继续递归使用这个过程
#include <stdio.h>
// 二分查找item插入位置的函数
int binarySearch(int a[], int item, int low, int high) {
// 如果范围缩小到一个元素
if (high <= low) {
// 如果要插入的元素大于当前元素,返回下一个位置,否则返回当前位置
return (item > a[low]) ? (low + 1) : low;
}
// 计算中间位置
int mid = (low + high) / 2;
// 如果找到了要插入的元素,则返回它的位置
if (item == a[mid]) {
return mid + 1;
}
// 递归地在左半部分或右半部分查找
if (item > a[mid]) {
return binarySearch(a, item, mid + 1, high);
}
return binarySearch(a, item, low, mid - 1);
}
// 折半插入排序算法
void binaryInsertionSort(int a[], int n) {
int i, loc, j, selected;
// 从第二个元素开始插入
for (i = 1; i < n; ++i) {
j = i - 1;
selected = a[i]; // 选择当前要插入的元素
// 找到要插入的位置
loc = binarySearch(a, selected, 0, j);
// 移动所有大于 selected 的元素一个位置向右
while (j >= loc) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = selected; // 插入 selected 到正确的位置
}
}
// 打印数组的函数
void printArray(int a[], int n) {
for (int i = 0; i < n; ++i) {
printf("%d ", a[i]);
}
printf("\n");
}
// 主函数
int main() {
int a[] = {12, 11, 13, 5, 6};
int n = sizeof(a) / sizeof(a[0]);
printf("原始数组: ");
printArray(a, n);
binaryInsertionSort(a, n);
printf("已排序数组: ");
printArray(a, n);
return 0;
}
初始数组资源 9 6 15 4 2 先取15
第一次排序后 【9 6 2 4】 15 再取9
第二次排序后 【6 2 4】 9 15 再取2
第三次排序后 2 【4 6】 9 15
排序算法比较
选择排序 | 冒泡排序 | 交换排序 | 插入排序 | 折半排序,又称快速排序,二分法 |
---|---|---|---|---|
每次选择所要排序数组中最大值(从小到大排序,则选择最小值)的数组元素,将这个数组元素的值与最前面没有进行排序的数组元素的值互换。 | 排序时,每次比较数组中相邻的两个数组元素的值,将较小的数排在较大的数前面(从小到大排列) | 交换排序是将每一位数与其后所有的数一一比较,如果发现符合条件的数据,则交换数据 | 工作原理是抽出一个数据,在前面的数据中寻找相应的位置插入,直到完成排序。 | 工作原理是先选择一个中间值middle(数组中间值),然后把比中间值小的数据放在左边,把比中间值大的放在右边,最后对两边继续递归使用这个过程。 |
共需要进行n(n-1)/2次比较;互相交换n-1次,适用于数量较小的排序 | 最好情况正序,比较一次即可;最坏的情况逆序,比较n^2次。稳定排序方法,排列有序时,效果好 | 正序最快,逆序最慢。排列有序时,效果好 | n-1次插入过程,恰好插入末端,则不需要移动数据,可以节省时间。因此基本有序在,那么算法具有较快的运算速度。 | n较大时,速度最快;n较小时,慢。不稳定的,对应又相同关键字的记录,排序后的结果可能会颠倒次序 |