zoukankan      html  css  js  c++  java
  • 八大排序 详解(中)

    接上篇博文——《八大排序 详解(上)》

    在这篇博文中本人就不过多解释排序的重要性了,接着是本人上篇博文——《八大排序 详解(上)》来讲,在这篇博文中,本人要进行讲解的是剩下的四大排序——插入排序、希尔排序(插入排序的进阶版)、桶排序以及归并排序

    五、插入排序
    插入排序的原理是:
    将所需排列的数组分为两半——已排和未排
    每次将未排的第一个数取出,然后从已排数组的第一个开始比较,遇到比它大的数,就插到那个数的前面。

    那么,我们现在用一张动态图来展示一下这个排序算法:
    在这里插入图片描述
    那么,用代码来实现的结果如下:

    void insertSort(int *array, int count) {
    	int i;
    	int j;
    	int t;
    	int tmp;
    
    	for (i = 1; i < count; i++) {
    		tmp = array[i];
    		for (j = 0; j < i && tmp > array[j]; j++)
    			;
    		for (t = i; t > j; t--) {
    			array[t] = array[t-1];
    		}
    		array[j] = tmp;
    	}
    }
    

    从这里我们能够发现,插入排序的时间复杂度是O(n ^2)。

    六、希尔排序(插入排序的进阶版):
    希尔排序和别的几大排序相比,算是比较中庸那种,因为它的最差情况和最优情况基本没多大差别,它的基本思想如下:
    首先,我们将每隔step个数的每个数放在一起,这样分好类之后,再用新的step分组,再进行如上操作(每个step都是数组长度每次除以2所得),直到step为0时结束

    现在,我们用一个动态图来实现这个排序算法:
    在这里插入图片描述
    而作为插入排序的进阶版,这个排序算法和插入排序算法的代码都基本一样。
    相关代码如下:

    static void insertSortOnce(int *array, int count, int start, int step) {
    	int i;
    	int j;
    	int t;
    	int tmp;
    
    	for (i = start + step; i < count; i += step) {
    		tmp = array[i];
    		for (j = start; j < i && tmp > array[j]; j += step)
    			;
    		for (t = i; t > j; t -= step) {
    			array[t] = array[t-step];
    		}
    		array[j] = tmp;
    	}
    }
    
    void ShellSort(int *array, int count) {
    	int step;
    	int start;
    
    	printf("
    Shell sort
    ");
    	for (step = count/2; step; step /= 2) {
    		for (start = 0; start < step; start++) {
    			insertSortOnce(array, count, start, step);
    		}
    	}
    }
    

    这里对上面的代码做下解释:
    第一个函数的类型前都有个static,意思是这个函数仅在该文件中使用,我们所编写的函数在接下来的代码中能够发现,提供给用户使用的只是这八大排序,至于构成这八大函数的子函数,不会提供给用户,这也是我们在数据结构与算法专题中要提到的,编写的.h的.c函数能够提供给外部使用的函数,在.h文件中声明;至于不能给外部使用的函数,就在.c文件中声明,我们在未来编程的过程中会了解到我们所做的工具函数和这里一样,并不是把所有的函数都提供给用户使用。

    从这里我们能够发现,希尔排序的时间复杂度是O(n ^(1.3 ~ 2))。

    七、归并排序:
    归并排序的基本思想是:
    分而治之,先两个两个比较,凑齐两组两两排好的组后,再进行四个四个比较,之后就是八个八个...直至比较的范围是整个数组的长度,待排完这轮后就结束排序。

    现在,我们通过一张动态图来展示下这个排序算法:
    在这里插入图片描述
    那么,相关代码如下:

    static void merge(int* array, int left, int right, int mid, int* temp) {
    	int i = left;
    	int j = mid + 1;
    	int tempLeft = left;
    	int t = 0;
    	
    	while (i <= mid && j <= right) {
    		temp[t] = array[i] <= array[j] ? array[i++] : array[j++];
    		t++;
    	}
    	while (i <= mid) {
    		temp[t++] = array[i++];
    	}
    	while (j <= right) {
    		temp[t++] = array[j++];
    	}								//以上三个循环的目的是将整个数组排好序再存入temp数组中
    
    	t = 0;
    	while (tempLeft <= right) {		//这个循环的目的是将排好序的数组内的值赋值给原数组
    		array[tempLeft++] = temp[t++];
    	}
    }
    
    static void mSort(int* array, int left, int right, int* temp) {
    	int mid;
    
    	if (left >= right) {
    		return;
    	}
    	
    	mid = (left + right) / 2;
    	mSort(array, left, mid, temp);
    	mSort(array, mid + 1, right, temp);
    	merge(array, left, right, mid, temp);
    
    }
    
    void mergeSort(int* array, int count) {
    	int *temp;
    	
    	temp = (int *)calloc(sizeof(int), count);
    	mSort(array, 0, count-1, temp);
    }
    

    从这里我们能够发现,归并排序的时间复杂度是O(n * log n)。

    八、桶排序:
    桶排序作为我们八大排序的最后一个来讲,是因为这个排序算法在我看来比较偏激,因为它变相地运用了“用空间换时间”的思想,它的大致原理如下:
    首先,我们放置10个桶,分别代表某一位为0~9哪一位的数都有谁,最后将桶中所有数取出放入原数组中,这样就完成了桶排序。

    现在,我们通过一张动态图来展示下这个排序算法:
    在这里插入图片描述
    那么,代码如下:

    //寻找原数组中的最大值
    static int findMaxNum(const int *array, int count) {
    	int max = array[0];
    	int i;
    
    	for (i = 1; i < count; i++) {
    		if (array[i] > max) {
    			max = array[i];
    		}
    	}
    
    	return max;
    }
    
    //寻找原数组中的最小值
    static int findMinNum(const int *array, int count) {
    	int min = array[0];
    	int i;
    
    	for (i = 1; i < count; i++) {
    		if (array[i] < min) {
    			min = array[i];
    		}
    	}
    
    	return min;
    }
    
    void bucketSort(int *array, int count){
    	int i = 0;
    	int j = 0;
    	int max = findMaxNum(array, count);
    	int min = findMinNum(array, count);
    	int length = max - min;	//通过最大值和最小值 来获取结果“桶”的容量
    
    	int *res = (int *)calloc(sizeof(int), length+1);
    
    	//用 结果数组中的适当下标的单元中的数,来记录垓下标在原数组中的出现次数
    	for (i = 0; i < count; i++) {
    		res[array[i] - min]++;
    	}
     
    	//为原数组赋排序后的值
    	for(i = 0; i <= length; ++i) {
    		while(res[i]--) {
    			array[j++] = i + min;
    		}
    	}
    	free(res);
    }
    

    我们可以在这里发现,桶排序的其实就是先放入桶中,再从桶中取出,放回原数组,这样下来,时间复杂度为O(n),但是空间复杂度比较高,所以它也算是很偏激那种排序算法,如果对时间需求高,这个排序算法无疑是最好的选择。

    那么,到目前为止,我们的八大排序就讲解完成了,希望同学们在看完本人的讲解之后能够有所收获!
    关于本人有关排序的最后一篇博文——《八大排序 详解(下)》,将会使用《八大排序 详解(上)》和本篇博文所编写的所有函数,并以一种十分凶悍的方法进行调用函数,也会用到本人之前的博文《指向函数的指针——消费未来》那篇所运用的知识,希望看到这里的同学能够耐心将下篇看完,谢谢!!!

    《八大排序 详解(上)》
    《八大排序 详解(下)》

  • 相关阅读:
    uboot中setenv和saveenv分析
    DMA和通道的区别
    openwrt 切换overlay文件系统为根文件系统
    华为SDN:解决传统网络3大问题
    企业需要申请多大宽带的专线?如何节省专线费用?
    stp
    inotify文件监控
    Qt中C++与QML交互
    内核空间可以直接访问应用层空间地址
    linux 提权漏洞总结
  • 原文地址:https://www.cnblogs.com/codderYouzg/p/12411928.html
Copyright © 2011-2022 走看看