参考:
插入排序
插入排序就是在之前排好的有序表中找到合适位置插入。
例如一个乱序的数组:{51,28,38,86,70,90,7,30,40,86,25}
- 第一个是51,此时还没有有序表,51作为有序表中的第一个。
- 28小于51,排在51前边
{28,51} - 38大于28小于51,排在28和51中间。
{28,38,51} - 86大于51,排在最后
{28,38,51,86}
…
直到排序完成。
代码
1234567891011121314151617181920212223 | void Sort(int arr[],int sz);int main(){ int arr[] = {51,28,28,86,-70,90,7,28,40,86,25}; int sz = sizeof(arr)/sizeof(arr[0]); Sort(arr,sz); return 0;}void Sort(int arr[],int sz){ int i; for (int i = 1; i < sz; i++) { int key = arr[i]; int j = i - 1; // 找到 key 的插入位置 while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; // 插入 key }} |
直接选择(简单)排序
例如一个数组:{51,28,38,86,70,90,7,30,40,86,25}
先找到这个数组中最小的数字,也就是7,把它和第一个数字,51交换位置,数组变成了:{(7),28,38,86,70,90,51,30,40,86,25}
再从这个数组的第二个数字开始寻找最小的数字,也就是25,和第二个数字28交换位置:{(7,25),38,86,70,90,51,30,40,86,28}
…
直到排序完成。
代码
123456789101112131415161718192021222324252627282930313233 | void Sort(int arr[],int sz);int main(){ int arr[] = {51,28,28,86,-70,90,7,28,40,86,25}; int sz = sizeof(arr)/sizeof(arr[0]); Sort(arr,sz); return 0;}void Sort(int arr[],int sz){ int i = 0; int j = 0; for (j=0; j<sz; j++) { int minValue = arr[j]; int minIndex = j; for (i=j+1; i<sz; i++)//找到最小的数字 { if (arr[i] < minValue) { minValue = arr[i];//更新最小的数字 minIndex = i;//最小数字的位置 } } if (minIndex != j)//只在必要时交换元素 { int temp = arr[j]; arr[j] = minValue; arr[minIndex] = temp; } }} |
冒泡排序
假设一个数组:{51,28,38,86,70,90,7,30,40,86,25}
51先与28进行比较,51>28,数组变成{28,51,38,86,70,90,7,30,40,86,25}
51再与38比较,51>38,数组变成{28,38,51,86,70,90,7,30,40,86,25}
…
直至第一轮排序完成,数组变为:{28,38,51,70,86,7,30,40,86,25,(90)}
可以看到,经过了第一轮排序,把最大的数字移到数组的末尾,之后不会再对这个数字进行排序。
再次进行第二轮冒泡排序:{28,38,51,70,86,7,30,40,86,25,(90)}
28与38比较,28<38,数组不变。
38再与51比较,38<51,数组不变。
…
86与7比较,86>7,数组改为:{28,38,51,70,7,86,30,40,86,25,(90)}
86与30比较,数组变成:{28,38,51,70,7,30,86,40,86,25,(90)}
86与40比较,数组变成:{28,38,51,70,7,30,40,86,86,25,(90)}
下次比较时,86与86相等,顺序不变,然后86再与25比较:{28,38,51,70,7,30,40,86,25,86,(90)}
经过第二轮冒泡排序,数组变成:{28,38,51,70,7,30,40,86,25,(86,90)}
下次再排序时,后两位不会再修改。
…
直到排序完毕。
代码
12345678910111213141516171819202122232425262728293031323334 | void Sort(int arr[],int sz);int main(){ int arr[] = {51,28,28,86,-70,90,7,28,40,86,25}; int sz = sizeof(arr)/sizeof(arr[0]); Sort(arr,sz); return 0;}void Sort(int arr[],int sz){ int i = 0; int j = 0; int swapped;//发生交换标记 for (j=0; j<sz-1; j++)//趟数 { swapped = 0; // 标记这一趟是否有交换 for (i=0; i<sz-j-1; i++)//一趟冒泡排序 { if (arr[i] > arr[i+1]) { int temp = arr[i]; arr[i] = arr[i+1]; arr[i+1] = temp; swapped = 1; // 有交换发生 } } // 如果没有交换,提前结束 if (!swapped) { break; } }} |
希尔排序
希尔排序首先需要一个步长,这个步长不是固定的,根据实际情况调整。
在这里我们取步长为d=(5,3,1)。
假设一个数组:{51,28,38,86,70,90,7,30,40,86,25}
步长为5,即51和90为一组,28和7为一组,38和30为一组,86和40为一组,70和86为一组,25单独为一组,本次不对其排序。
进行第一趟排序,不同组进行分别比较:
- 51<90,这组顺序不改变
- 28>7,把28和7调换位置
- 38>30,调换位置
- 86>40,调换位置
- 70<86,不变
- 25单独一组,不变
进行第一趟排序后,数组变为:{51,7,30,40,70,90,28,38,86,86,25}
再以步长为3,在第一次排序后的基础上,进行第二趟希尔排序:{51,7,30,40,70,90,28,38,86,86,25}
51和40为一组,7和70为一组,30和90为一组,28和86为一组,38和25为一组,倒数第三个数86单独一组。
- 51>40,调换位置
- 7<70,不变
- 30<90,不变
- 28<86,不变
- 38>25,调换位置
- 86单独一组,位置不变
按照上面进行第二趟希尔排序:{40,7,30,51,70,90,28,25,86,86,38}
再以步长为1,进行第三趟希尔排序:
- 40先和7比较,调换位置
{7,40,30,51,70,90,28,25,86,86,38} - 40和30比较,调换位置
{7,30,40,51,70,90,28,25,86,86,38} - 40和51比较,不变
- 51和70比较,不变
- 70和90比较,不变,90和28比较,调换位置
代码
12345678910111213141516171819202122232425 | void Sort(int arr[],int sz);int main(){ int arr[] = {51,28,28,86,-70,90,7,28,40,86,25}; int sz = sizeof(arr)/sizeof(arr[0]); Sort(arr,sz); return 0;}void Sort(int arr[],int sz){ int gap,i,j,temp; for (gap = sz / 2; gap > 0; gap = gap / 2)//先定义步长 { for (i = gap; i < sz; i++)//元素间移动位置 { for (j = i - gap; j>=0 && arr[j]>arr[j+gap]; j = j - gap)//比较各相距离gap个位置的元素 { temp = arr[j];//更换位置 arr[j] = arr[j+gap]; arr[j+gap] = temp; } } }} |
快速排序
先选出一个节点(取有意义的,或者取第一个),把这个节点放在一个数组的中间,把要排序的数字中小于它的放在它的左侧,右侧都是大于它的数字,最后对两边的数字进行排序。
假设一个数组{51,28,38,86,70,90,7,30,40,86,25}
选取数组中第一个数字作为节点P,最左边为L指针,最右边为R指针。
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
P节点在最左边,要先从最右边的R指针开始比较,由于25<51,把25放在左边。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 |
接下来L指针右移,由于28<51,把28放在左边,L指针右移。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 |
L指针指向的38<51,把38放在左边,L指针右移。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 |
L指针指向的86>51,86去R指针所在位置,接下来左移R指针。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 | 86 |
R指针指向的86>51,86放在右边,R指针左移。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 | 86 | 86 |
R指针指向的40<51,40移动到L指针所在的位置,接下来右移L指针。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 | 40 | 86 | 86 |
L指针指向的70>51,70移动到R指针所在的位置,接来下左移R指针。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 | 40 | 70 | 86 | 86 |
R指针指向的30<51,30移动到L指针所在的位置,接下来右移L指针。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 | 40 | 30 | 70 | 86 | 86 |
L指针指向的90>51,90移动到R指针所在位置,接下来左移R指针。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️P | ||||||||||
| ⬆️L | ⬆️R | |||||||||
| 25 | 28 | 38 | 40 | 30 | 90 | 70 | 86 | 86 |
R指针指向的7<51,7移动到L指针位置,接下来右移L指针,L和R指针汇合,把P指针(51)移动到这里。⬇️
| 51 | 28 | 38 | 86 | 70 | 90 | 7 | 30 | 40 | 86 | 25 |
|---|---|---|---|---|---|---|---|---|---|---|
| ⬆️R⬆️L | ||||||||||
| 25 | 28 | 38 | 40 | 30 | 7 | 51 | 90 | 70 | 86 | 86 |
| ⬆️P |
接下来把P指针左侧和右侧作为两个单独的数组,再次排序,直到数组有序。
代码
1234567891011121314151617181920212223242526272829303132333435363738394041 | void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp;}int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选择最后一个元素作为基准 int i = (low - 1); // 小于基准的元素索引 for (int j = low; j < high; j++) { if (arr[j] < pivot) { i++; swap(&arr[i], &arr[j]); // 交换 } } swap(&arr[i + 1], &arr[high]); // 将基准放到正确位置 return (i + 1);}void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); // 找到基准元素的索引 quickSort(arr, low, pi - 1); // 对基准左侧进行排序 quickSort(arr, pi + 1, high); // 对基准右侧进行排序 }}void printArray(int arr[], int n) { for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n");}int main() { int arr[] = {51, 28, 38, 86, 70, 90, 7, 30, 40, 86, 25}; int n = sizeof(arr) / sizeof(arr[0]); printf("原数组: "); printArray(arr, n); quickSort(arr, 0, n - 1); printf("排序后数组: "); printArray(arr, n); return 0;} |