本人录制技术视频地址:https://edu.csdn.net/lecturer/1899 欢迎观看。
本节中所讲的排序均以升序为例。
一、冒泡排序
1. 基本思想:
从左到右,两两比较;如果发现前者比后者大,则交换元素。每一轮比较完毕后,序列中最大的一个元素会至于最后。流程图如下:
2. 代码清单:
void bubbleSort(int *a, int length) {
int i,j;
for (i = length - 1; i >= 0; i--) {
for (j = 0; j < i; j++) {
if (a[j] > a[j + 1]) {
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
}
int main(int argc, const char * argv[]) {
int a[] = {2, 4, 9, 1, 0, 3};
bubbleSort(a, 6);
for (int i = 0; i < 6; i++) {
printf("%d\n", a[i]);
}
return 0;
}
二、选择排序
1. 基本思想:
每次循环的时候,找出数组中最小的元素,并且与循环操作中数组最前面的元素进行交换。流程图如下:
2. 代码清单:
void selectionSort(int *a, int length) {
int outer, inner, min;
for (outer = 0; outer < length - 1; outer++) {
min = outer;
for (inner = outer + 1; inner < length; inner++) {
if (a[inner] < a[min]) {
min = inner;
}
}
int temp = a[outer];
a[outer] = a[min];
a[min] = temp;
}
}
int main(int argc, const char * argv[]) {
int a[] = {2, 4, 9, 1, 0, 3};
selectionSort(a, 6);
for (int i = 0; i < 6; i++) {
printf("%d\n", a[i]);
}
return 0;
}
三、插入排序
1. 基本思想:
每次假定数组第一个元素为在正确的位置上面,然后在数组后面依次寻找比这个元素大得并且是最小的那个元素,将其插入到指定元素的后面,与此同时,那些原本紧挨着指定元素后面的所有元素,依次往后移动一个位置。
2. 代码清单:
void insertSort(int *a, int length) {
int i, j, target;
// 假定第一个元素被放到了正确的位置上,这样仅需要便利n-1次
for (i = 1; i < length; i++) {
j = i;
target = a[i];
while (j > 0 && target < a[j - 1]) {
a[j] = a[j - 1];
j--;
}
a[j] = target;
}
}
int main(int argc, const char * argv[]) {
int a[] = {4, 2, 6, 1, 8, 3};
insertSort(a, 6);
for (int i = 0; i < 6; i++) {
printf("%d\t", a[i]);
}
return 0;
}
四、归并排序
1. 基本思想:
将一个数组分解成多个数组,依次对每个子数组进行排序,最终将排序完成的子数组合并,进行最终的排序。
2. 代码清单:
void merge(int a[], int p, int q, int r) {
int i, j, k, n1, n2;
// 变量用于申请两个内存空间
int *front, *back;
// 前一部分长度
n1 = q - p + 1;
// 后一部分长度
n2 = r - q;
// 申请两个空间存放拍好的数组
front = (int *)malloc(n1 * sizeof(int));
back = (int *)malloc(n2 * sizeof(int));
// 将数组转入两个新空间中
for (int i = 0; i < n1; i++) {
front[i] = a[p + i];
}
for (int i = 0; i < n2; i++) {
back[i] = a[q + i + 1];
}
// 将元素合并
i = 0; j = 0; k = p;
while (i < n1 && j < n2) {
if (front[i] < back[j]) {
a[k++] = front[i++];
} else {
a[k++] = back[j++];
}
}
// 将剩余元素合并
while (i < n1) {
a[k++] = front[i++];
}
while (j < n2) {
a[k++] = back[j++];
}
}
void marge_sort(int a[], int p, int r) {
int q;
if (p < r) {
q = (p + r) / 2;
marge_sort(a, p, q);
marge_sort(a, q + 1, r);
merge(a, p, q, r);
}
}
int main(int argc, const char * argv[]) {
int a[8] = {1, 6, 4, 5, 3, 9, 7, 8};
marge_sort(a, 0, 7);
for (int i = 0; i < 8; i++) {
printf("%d\t", a[i]);
}
return 0;
}
五、快速排序
1. 基本思想:
假设用户输入了如下数组:
下标
|
0
|
1
|
2
|
3
|
4
|
5
|
数据
|
6
|
2
|
7
|
3
|
8
|
9
|
创建变量i=0(指向第一个数据), j=5(指向最后一个数据), k=6(赋值为第一个数据的值)。
我们要把所有比k小的数移动到k的左面,所以我们可以开始寻找比6小的数,从j开始,从右往左找,不断递减变量j的值,我们找到第一个下标3的数据比6小,于是把数据3移到下标0的位置,把下标0的数据6移到下标3,完成第一次比较:
下标
|
0
|
1
|
2
| 3 |
4
|
5
|
数据
|
3
|
2
|
7
|
6
|
8
|
9
|
i=0 j=3 k=6
接着,开始第二次比较,这次要变成找比k大的了,而且要从前往后找了。递加变量i,发现下标2的数据是第一个比k大的,于是用下标2的数据7和j指向的下标3的数据的6做交换,数据状态变成下表:
下标
|
0
|
1
|
2
|
3
|
4
|
5
|
数据
|
3
|
2
|
6
|
7
|
8
|
9
|
i=2 j=3 k=6
称上面两次比较为一个循环。
接着,再递减变量j,不断重复进行上面的循环比较。
在本例中,我们进行一次循环,就发现i和j“碰头”了:他们都指向了下标2。于是,第一遍比较结束。得到结果如下,凡是k(=6)左边的数都比它小,凡是k右边的数都比它大:
下标
|
0
|
1
|
2
|
3
|
4
|
5
|
数据
|
3
|
2
|
6
|
7
|
8
|
9
|
如果i和j没有碰头的话,就递加i找大的,还没有,就再递减j找小的,如此反复,不断循环。注意判断和寻找是同时进行的。
然后,对k两边的数据,再分组分别进行上述的过程,直到不能再分组为止。
2. 代码清单:
void sort(int *a, int left, int right) {
// 表示一组排序结束
if (left > right) {
return;
}
int i = left; int j = right; int key = a[left];
while (i < j) {
// 找到比key小的值,交换位置(放在左边)
while (i < j && key <= a[j]) {
j--;
}
a[i] = a[j];
// 找到比key大的值,交换位置(放在右边)
while (i < j && key >= a[i]) {
i++;
}
a[j] = a[i];
}
a[i] = key;
// 递归执行
sort(a, left, i - 1);
sort(a, i + 1, right);
}
int main(int argc, const char * argv[]) {
int a[] = {3, 5, 8, 1, 0, 2};
sort(a, 0, 5);
for (int i = 0; i < 6; i++) {
printf("%d\t", a[i]);
}
return 0;
}