博主主页:@ᰔᩚ. 一怀明月ꦿ
❤️专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++
座右铭:“不要等到什么都没有了,才下定决心去做”
大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点
目录
冒泡排序
选择排序
插入排序
堆排序
希尔排序
五种排序的效率比较
从左到右,相邻元素进行比较。每次比较之后,就会找到待排数据中最大的一个或者最小的一个,这个数就会从待排数据的最右边冒出来。
以从升序为例,第一次比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。这里所有排序都以升序为例
//升序 #include
void Print(int arr[],int len) { for(int i=0;i arr[j+1]) { int temp=arr[j]; arr[j]=arr[j+1]; arr[j+1]=temp; } } } Print(arr,len); } int main() { int arr[]={9,8,7,6,0,5,4,3,2,1}; int len=sizeof(arr)/sizeof(*arr); Buble_sort(arr,len); return 0; } 结果:0 1 2 3 4 5 6 7 8 9
选择排序(Choose sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的中数据元素选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
//升序 #include
void Print(int arr[],int len) { for(int i=0;i arr[j]) { int temp=arr[j]; arr[j]=arr[i]; arr[i]=temp; } } } Print(arr,len); } int main() { int arr[]={9,8,7,6,0,5,4,3,2,1}; int len=sizeof(arr)/sizeof(*arr); Choose_sort(arr,len); return 0; } 结果:0 1 2 3 4 5 6 7 8 9
将待排序序列分为两部分,一部分有序一部分无序,我们把第一个元素看作有序序列,从第二个元素到最后为无序序列,将无序序列中每一个元素依次插入到有序序列的合适位置–从小到大(从大到小)。
#include
void Print(int arr[],int len) { for(int i=0;i =0;j--) { if(temp
堆排序(HeapSort)就是利用堆(一种数据结构,如果不了解堆,可以看我前面文章了解一下堆)进行排序的方法 。基本思想:将待排序的序列构造成一个大根堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次小值。如此反复执行,就能得到一个有序序列
主要步骤:建堆(大根堆),调整(向下调整)
#include
//两数交换 void Swap(int* e1,int* e2) { int temp=*e1; *e1=*e2; *e2=temp; } //向上调整 void AdjustUP(int* a,int n) { int child=n-1; int parent=(child-1)/2; while(child>0) { if(a[child]a[parent]) { Swap(&a[child], &a[parent]); parent=child; child=parent*2+1; } else { break; } } } //向上建堆排序 //时间复杂度为O(N*logN) void HeapSort_UP(int* a,int n) { //向上建堆是从第二层开始直到第h层,所以其时间复杂度为O(N*logN) for(int i=1;i 0) { Swap(&a[0], &a[end]); AdjustDown(a, end,0); end--; } } //向下建堆排序 //时间复杂度为N*logN void HeapSort_Down(int* a,int n) { //向下建堆是从第h-1层直到第一层,所以其时间复杂度为O(N) for(int i=(n-1-1)/2;i>=0;i--) { AdjustDown(a, n,i); } int end=n-1; //建堆完成后,需要进行向下调整其时间复杂度为O(N*logN) while(end>0) { Swap(&a[0], &a[end]); AdjustDown(a, end,0); end--; } } 总结:向上建堆从第二层开始直到第h层,向下建堆是从第h-1层直到第一层,虽然它们经历的层数相同,但是向上建堆中第一层不用调整,向下建堆中第h层不用调整(h为最后一层),第一层的元素只有一个,第h层元素有2^(h-1)个。所以他们的时间复杂度不同,向上建堆为O(N*logN),向下建堆为O(N) int main() { int a[]={1,3,5,7,9,0,8,6,4,2}; int n=sizeof(a)/sizeof(a[0]); //HeapSort_UP(a,n); HeapSort_Down(a, n); for(int i=0;i
希尔排序是对插入排序进行优化,希尔排序先选定一个数值(整数)作为增量,把待排序所有数据分为若干组,以每个距离(这个距离就是增量)的等差数列为一组,对每一组进行排序,这一步叫作预排序,然后将增量缩小,继续分组排序,重复上述动作,直到增量缩小为1时,排序完正好有序。
希尔排序原理是每一对分组进行排序后,整个数据就会更接近有序,当增量缩小为1时,就是插入排序,但是现在的数组非常接近有序,移动的数据很少,所以效率非常高,所以希尔排序又叫减小增量排序。
每次排序让数组接近有序的过程叫做预排序,最后一次插入是直接插入排序
希尔排序 1.预排序--接近有序 2.插入排序 间隔gap分为一组,总计gap组 假设gap==3; 预排序:对gap组数据分别进行插入排序 gap越大,大的数可以更快到后面,小的数 #include
void Print(int* a,int n) { for(int i=0;i 1)//时间复杂度log3^N { gap=gap/3+1; // for(int j=0;j =0)//log3^N { if(a[end]>temp) { a[end+gap]=a[end]; end-=gap; } else { break; } } a[end+gap]=temp; } // } } Print(a, n); return 0; } 结果:0 1 2 3 4 5 6 7 8 9
其实这里是六种排序,我在这里加入了 C 语言库里的快速排序qsort,为了更好比较各个排序的效率。这里采用六种排序同时排序具有 相同10000 个数据的数组。
#include
#include #include //打印函数 void Print(int* a,int n) { for(int i=0;i a[child+1]) { child++; } if(a[child]=0;i--) { AdjustDown(a, n, i); } int end=n-1; while(end>0) { Swap(&a[0], &a[end]); AdjustDown(a, end, 0); end--; } } //冒泡排序 void BubbleSort(int* a,int n) { for(int i=0;i a[j+1]) Swap(&a[j], &a[j+1]); } } } //选择排序 void SelectSort(int* a,int n) { for(int i=0;i a[j]) Swap(&a[i], &a[j]); } } } //插入排序 void InsertSort(int* a,int n) { for(int i=0;i =0) { if(a[end]>temp) { a[end+1]=a[end]; end--; } else { break; } } a[end+1]=temp; } } //希尔排序 void SellSort(int* a,int n) { int gap=n; while(gap>1) { gap=gap/3+1; for(int i=0;i =0) { if(a[end]>temp) { a[end+gap]=a[end]; end-=gap; } else { break; } } a[end+gap]=temp; } } } int cmp_int(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } int main() { srand((unsigned int)time(NULL)); const int N=10000; int* a1=(int*)malloc(sizeof(int)*N); int* a2=(int*)malloc(sizeof(int)*N); int* a3=(int*)malloc(sizeof(int)*N); int* a4=(int*)malloc(sizeof(int)*N); int* a5=(int*)malloc(sizeof(int)*N); int* a6=(int*)malloc(sizeof(int)*N); for(int i=0;i 结果:
泡排序所需的时间:389679ms
选择排序所需的时间:165760ms
堆排序所需的时间:3005ms
插入排序所需的时间:75965ms
希尔排序所需的时间:1628ms
快排排序所需的时间:585ms
可见快排、希尔排序和堆排序是一个量级,其中快排的效率非常高,不可思议的是希尔排序的效率高过了时间效率为O(N*logN)的堆排序,虽然希尔排序的中循环比较多,但是时间效率并不高,因为希尔排序的时间效率存在难以解决的数学难题,所以很难精确其时间效率,希尔排序的时间效率大概是 O(N^1.3)。插入排序、选择排序和冒泡排序,这三种排序的时间效率都为O(N^2),其中插入排序的效率明显高于其他两个,冒泡排序的效率非常低,没有实际的用途,常用于教学。
如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家!