C语言排序
一、冒泡排序
基本思想:(将相邻两个数比较,小的调到前头)
1)有n个数(存放在数组a(n)中),第一趟将每相邻两个数比较,小的调到前头,经n-1次两两相邻比较后,最大的数已“沉底”,放在最后一个位置,小数上升“浮起”;
2)第二趟对余下的n-1个数(最大的数已“沉底”)按上法比较,经n-2次两两相邻比较后得次大的数;
3)依次类推,n个数共进行n-1趟比较,在第j趟中要进行n-j次两两比较
#include <stdio.h> #include <windows.h> int main() { int a[10] = { 123, 34, 76, 31, 678, 94, 456, 29, 4, 23 }; for (int j = 0; j < 10; j++) { for (int i = 0; i < 9; i++) { if (a[i] > a[i + 1]) { int b = 0; b = a[i + 1]; a[i + 1] = a[i]; a[i] = b; for (int k = 0; k < 10; k++){ printf("%d\t", a[k]); }printf("\n"); Sleep(500); } } } }
二、选择排序
基本思想:
1)对有n个数的序列(存放在数组a(n)中),从中选出最小的数,与第1个数交换位置;
2)除第1 个数外,其余n-1个数中选最小的数,与第2个数交换位置;
3)依次类推,选择了n-1次后,这个数列已按升序排列。
#include <stdio.h> #include <windows.h> int main() { int a[10] = { 123, 34, 76, 31, 678, 94, 456, 29, 4, 23 }; for (int i = 0; i < 10; i++) { int min = i; //这个十分重要,每次循环之前初始化min的值 并且不再重复用前面的下标 for (int j = i; j < 10; j++) //这个循环找出最小的那个值的下标 { if (a[j] < a[min]) { min = j; } } if (a[min] != a[i]) //把刚才找到的那个min下标和前面他排名的位置互换 { int b = a[min]; a[min] = a[i]; a[i] = b; } for (int k = 0; k < 10; k++){ printf("%d\t", a[k]); }printf("\n"); } }
三、直接插入排序
基本思想:
1)第一个元素自己作为一个有序数组;
2)从第二个元素开始,将它与其左侧第一个元素比较,若左侧第一个元素比它大,则继续与左侧第二个元素比较,直到遇到不大于(小于或等于)该元素的元素,将该元素插入到所找到的元素的右边,此时该元素及其左边的元素是已排序的;
3)选取第 3、4、...、n 个元素,重复步骤 2;
4)得到有序的数
#include <stdio.h> #include <windows.h> int main() { int a[10] = { 123, 34, 76, 31, 678, 94, 456, 29, 4, 23 }; for (int i = 1; i < 10; i++)//从第二个数开始 { int b = a[i]; int p = i - 1; while (p >= 0 && b < a[p])//把所有比a[i]大的数全换到后面去 { a[p + 1] = a[p]; p--; } a[p + 1] = b; for (int k = 0; k < 10; k++){ printf("%d\t", a[k]); }printf("\n"); } }
四、希尔排序
首先、先把一个数组按照一定间隔,分成两两一组的结合,同时对比这两个数据,排序
然后、再按照另一个间隔重复刚才的步骤
接下来、直到间隔为1,也就是相邻的两个数据为一组,做一次直插排序
间隔一般为数组长度的1/2,第二次为1/4,第三次1/8以此类推,直到间隔为1
下列代码中,排序的部分和上面直插排序完全一致。
#include <stdio.h> #include <windows.h> int main() { int a[10] = { 123, 34, 76, 31, 678, 94, 456, 29, 4, 23 }; int d; //每次排序的间隔值 int x = 0; //中间变量 int n = 10; //数组长度 d = n / 2; //初始间隔为数组长度的一半 while (d >= 1) //当间隔为1的时候,使用一次插入排序 { for (int i = d; i < n; i++) { x = a[i]; int j = i - d; while (j >= 0 && a[j]>x) //使用a[j]和a[i]作为一对去排序 { a[i] = a[j]; j = j - d; } a[j + d] = x; } d = d / 2; for (int k = 0; k < 10; k++){ printf("%d\t", a[k]); }printf("\n"); } }
四、快速排序
第一步,选择一个数作为基准(本例中选择数组最前端那个)
第二步,将后面的所有数字里面,比基数小的放左边,比基数大的放右边
第三步,不断重复第二步。。。
本例中使用左右指针。
#include <stdio.h> void change(int *a, int *b); void Sequence(int a[], int q, int p); int main() { int a[10] = { 12, 13, 15, 20, 0, -1, -10, 100 ,13 ,1}; Sequence(a, 0, 9); for (int k = 0; k < 10; k++){ printf("%d\t", a[k]); }printf("\n"); } /*互换位置 */ void change(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } /*快速排序函数 参数说明: a[] 待排数组 q 左指针的位置 p 右指针的位置 */ void Sequence(int a[], int q, int p) { int q_1 = q;//q一开始的位置 int p_1 = p;//p一开始的位置 int basis = a[q];//基准数据 取数组的第一个数 //当左右指针相遇时不循环了,此时q=基数所应该在的位置 if (q >= p){ return; } while (q < p) { //先走p //a[p]和基数比较,如果比基数大,指针向前挪动,如果比基数小,则和a[q]换位 while (q < p && a[p] > basis) { p--; } change(&a[q], &a[p]); q++; //a[q]和基数比较,只要a[q]比基数小,就往右走,直到走到比基数大的数,就和a[p]换位 while (q < p && a[q] < basis) { q++; } change(&a[q], &a[p]); p--; } a[q] = basis;//将最开始选定的基数,赋值给q指针最后指向的地方,也就是basis本应在的位置 /* 到这里,第一次循环已经结束了,但是还需要对左右两个大小数组各进行快排 所以,这两个数组,{0→q-1},{q+1→p}还需要再用同样的方法进行排序 */ //此时,q已经是基准数basis所在的位置了,利用一开始存的变量区域放进函数 Sequence(a, q_1, q - 1); Sequence(a, q + 1, p_1); }
123, 34, 76, 31, 678, 94, 456, 29, 4, 23