C语言中文网学习笔记
1.冒泡排序
以从小到大排序为例,冒泡排序的整体思想是这样的:
- 从数组头部开始,不断比较相邻的两个元素的大小,让较大的元素逐渐往后移动(交换两个元素的值),直到数组的末尾。经过第一轮的比较,就可以找到最大的元素,并将它移动到最后一个位置。
- 第一轮结束后,继续第二轮。仍然从数组头部开始比较,让较大的元素逐渐往后移动,直到数组的倒数第二个元素为止。经过第二轮的比较,就可以找到次大的元素,并将它放到倒数第二个位置。
- 以此类推,进行 n-1(n 为数组长度)轮“冒泡”后,就可以将所有的元素都排列好。
未优化排序:需要比较n+1轮
#include <stdio.h>
#pragma warning(disable:4996)
int main() {
int arr[10] = { 7,5,4,1,2,3,6,8,9 };
int i, j,temp;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int c = 0; c < 10; c++) {
printf("%d ", arr[c]);
}
return 0;
}
优化排序:加入isSorted判断是否已排序
#include <stdio.h>
#pragma warning(disable:4996)
int main() {
int arr[10] = { 7,5,4,1,2,3,6,8,9 };
int i, j,temp,isSorted;
for (i = 0; i < 9; i++) {
isSorted=1;
for (j = 0; j < 9 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
isSorted = 0;
}
}
if (isSorted)break;
}
for (int c = 0; c < 10; c++) {
printf("%d ", arr[c]);
}
return 0;
}
2.快速排序
(1)定义两个变量low和high,将low、high分别设置为要进行排序的序列的起始元素和最后一个元素的下标。第一次,low和high的取值分别为0和n-1,接下来的每次取值由划分得到的序列起始元素和最后一个元素的下标来决定。
(2)定义一个变量key,接下来以key的取值为基准将数组A划分为左右两个部分,通 常,key值为要进行排序序列的第一个元素值。第一次的取值为A[0],以后毎次取值由要划 分序列的起始元素决定。
(3)从high所指向的数组元素开始向左扫描,扫描的同时将下标为high的数组元素依次与划分基准值key进行比较操作,直到high不大于low或找到第一个小于基准值key的数组元素,然后将该值赋值给low所指向的数组元素,同时将low右移一个位置。(4)如果low依然小于high,那么由low所指向的数组元素开始向右扫描,扫描的同时将下标为low的数组元素值依次与划分的基准值key进行比较操作,直到low不小于high或找到第一个大于基准值key的数组元素,然后将该值赋给high所指向的数组元素,同时将high左移一个位置。
(5)重复步骤(3) (4),直到low的植不小于high为止,这时成功划分后得到的左右两部分分别为A[low……pos-1]和A[pos+1……high],其中,pos下标所对应的数组元素的值就是进行划分的基准值key,所以在划分结束时还要将下标为pos的数组元素赋值 为 key。
(6)将划分得到的左右两部分A[low……pos-1]和A[pos+1……high]继续采用以上操作步骤进行划分,直到得到有序序列为止。
这是中文网资料里的解释(初学者的我看着有点烧脑),查找了不同人的分析。
整理了一下:
1.快速排序是设置一个key值(一般是arr[0]或arr[n-1]),通过循环移动这个key值,来让这个key值的左边的数全部小于key,右边全部大于key。以移动后key的位置作为pos分为两个部分,再分别递归两个部分,pos位置就不用变化了。两个部分分别为:arr[start,pos-1]和arr[pos+1,end]。即第一次循环后:arr[0,pos-1],arr[pos+1,n-1]。
2.
如何移动这个key,正如图中,key=arr[0]==32.
循环1:拿arr[high]同key比较,若大于key,high左移继续循环比较直到low和high相遇,或者找到一个比key小的数,图中23<32,将23赋值到arr[0]。
循环2:low右移到12的位置,同key比较,12<32,low继续右移,循环操作,直到low与high相遇,或者找到一个比key大的数,图中的78,将这个78赋给high的位置,并且high左移。回到循环1。
直到low与high相遇,分割成为两个部分。这个时候low就是pos。
3.排序算法最后将2点中的循环持续递归,直到无法分割,也就是分割的部分start等于end。
void quick_sort(int arr[],int start,int end){
int pos;//定义pos
if(start<end){//判断是否还能切割
pos = partition(arr,start,end);//partiton函数是实现2点中的循环,排序一次,返回pos值。
quick_sort(arr,start,pos-1);
quick_sort(arr,pos+1,end); //分割部分递归,直到无法分割。
}
}
4.完整代码:
#include <stdio.h>
#pragma warning(disable:4996)
int partition(int arr[], int low, int high) {
int key = arr[low];
while (low < high) {
while (low < high && arr[high] >= key) {
high--;
}
if (low < high) {
arr[low++] = arr[high];
}
while (low < high && arr[low] <= key) {
low++;
}
if (low < high) {
arr[high--] = arr[low];
}
}
arr[low] = key;
return low;
}
void quick_sort(int arr[], int start, int end) {
int pos;
if (start < end) {
pos = partition(arr, start, end);
quick_sort(arr, start, pos - 1);
quick_sort(arr, pos + 1, end);
}
}
int main() {
int arr[6] = { 2,5,6,7,1,0};
quick_sort(arr, 0, 5);
for (int i = 0; i < 6; i++) {
printf("%d ", arr[i]);
}
return 0;
}