当前位置: 首页 > news >正文

永康网站网站建设深圳优化网站公司哪家好

永康网站网站建设,深圳优化网站公司哪家好,网站改版的步骤,门户网站的建设1.归并排序 基本思想: 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个…

1.归并排序

基本思想:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:

相当于每次把待排数据分为两个子区间,如果每个子区间有序,再让两个子区间归并起来也有序,那整体就有序了。我们可以按照二叉树的思想,把子区间再分为两份,使子区间的子区间有序.......直到子区间分无可分为止。

具体过程如下:

那该如何让两个有序子区间归并呢?

直接在数组中肯定不行,这样会发生数据的覆盖。所以我们可以像之前合并两个有序数组一样,另外开辟一个空间tmp,依次比较两个有序子区间的值,每次比较后把较小的放在tmp中,如果其中一个子区间提前结束,就把另外一个子区间的剩余的数据全放进tmp,最后把tmp中的数据拷贝回原数组。

使用递归实现:

#include<stdio.h>
#include<stdlib.h>
void _MegeSort(int* a, int begin, int end,int*tmp)
{//只剩一个数据,递归结束if (begin == end){return;}int mid = (begin + end) / 2;//递归子区间,分为两部分_MegeSort(a, begin, mid, tmp);_MegeSort(a, mid+1, end, tmp);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int j = begin;//两部分比较,每次小的放入tmpwhile (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}//哪部分有剩余,全部放入tmpwhile (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}//拷贝到原数组memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MegeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);_MegeSort(a, 0, n - 1, tmp);free(tmp);
}void Print(int* a, int n)
{for (int i = 0; i < n; i++){printf("%d ",a[i]);}printf("\n");
}
int main()
{int a[] = { 1,4,9,6,3,5,2,8,10,7,11,1};MegeSort(a, sizeof(a) / sizeof(int));Print(a, sizeof(a) / sizeof(int));return 0;
}

注意:

1. 因为每次递归的子区间都不一定是从0开始的,所以我们拷贝数据时,最好从begin的位置开始:

//拷贝到原数组
memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));

2. 在代码中j作为tmp的坐标,每次往tmp中放入数据后都要加一,但不能初始化为0,否则每次递归进入,j的值都会清0,所以最好初始化:j=begin

归并排序的复杂度:

时间复杂度O(N*logN)

归并排序每次递归都要把待排数据分为两份,相当于二分法,那一共有logN层递归,而每次递归都要比较数据,要把每个数据都遍历一遍,每层的时间复杂度就是O(N),所以总共的时间复杂度是O(N*logN)。

空间复杂度:O(N) 

刚开始就开辟了空间,此时就已经是O(N)了,而递归过程中函数栈帧的创建是logN,所以总的空间复杂度是:O(N+logN),但是量级没变,还是O(N)。

2.非递归实现归并排序

非递归实现归并排序,我们只需模拟上述的递归过程即可,把递归过程转换为:把数据先分为2个一组,全部归并一遍,拷贝回原数组,然后4个一组,全部归并一遍,拷贝回原数组,再8个一组, 全部归并一遍,拷贝回原数组,

那我们就可以设置一个gap,两个数据为一组时,gap=1,每归并一组数据就往后跳2*gap步,直到全部归并一遍,再次分组,这次gap=2,每归并一组数据往后跳2*gap步,直到全部归并一遍,下次gap=4,跳2*gap步.....,直到gap>n就停止,

代码如下:

void MegeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail\n");return;}int gap = 1;while (gap < n){int j = 0;for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//两部分比较,每次小的放入tmpwhile (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}//哪部分有剩余,全部放入tmpwhile (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}}memcpy(a, tmp, sizeof(int) * n);gap *= 2;}free(tmp);
}

测试一下:

上面结果看起来,我们排序成功了,但是上述代码真的对吗?

上面代码我们在测试时用的是8个数据,但是如果用9个、10个等,就会发现排序并不会成功,可能程序还会崩掉,这是为什么呢?

因为我们在分组时,是按照固定的2的次方分的,一旦数据个数不是2、4、8的次方,后面归并时就会发生越界问题。

下面我们给10个数据打印一下边界,会发现,有三种越界的方式,:

那我们对这三种情况分别做一下处理:

第1、2种情况出现时,我们直接break,第三种情况,我们修改边界,令end2=n-1,但是注意直接break后,第1、2种情况往tmp中归并时会少一部分数据(如上图蓝框所示),所以最后把tmp的数据往a中拷贝时,不能一次性全部拷贝回去,否则a中这些数据就永远丢失了,所以最好归并一段,拷贝一段,这样拷贝过去的数据只会把前面的数据覆盖,没参与归并的数据还在a中。

代码如下:

void MegeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail\n");return;}int gap = 1;while (gap < n){int j = 0;for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;if (end1 >= n || begin2 >= n){break;}//修正if (end2 >= n){end2 = n - 1;}//两部分比较,每次小的放入tmpwhile (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}//哪部分有剩余,全部放入tmpwhile (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}//归并一段,拷贝一段memcpy(a+i, tmp+i, sizeof(int) * (end2-i+1));}gap *= 2;}free(tmp);
}

3.计数排序

基本思想:

1. 统计每个数据出现的次数。

2. 根据数据的次数排序。 

如果我们要排序的数在0~9之间,我们可以像上面一样开辟10个int大小的空间,统计待排数据中每个数据的个数,在开辟出的数组的相应下标处计数,那如果我们要排序的数据在100~109之间呢?难道开辟110个空间吗?

当然不是,我们可以做相对映射,在开辟空间之前,先找到待排数据中的最小值和最大值,开辟空间的大小就是:sizeof(int)*(max-min+1),开辟出的数组下标应该是:0~9,0~9下标的位置分别对应的是100~109,计数时,在下标为该数据减待排数据中的最小值的位置统计次数,例如:109就在109-100=9的下标处统计次数,统计完排序的时候再加上最小值即可。

代码如下:

#include<stdio.h>
#include<stdlib.h>
void CountSort(int* a, int n)
{int min = a[0], max = a[0];//找最大值和最小值for (int i = 0; i < n; i++){if (a[i] < a[0]){min = a[i];}if (a[i] > a[0]){max = a[i];}}int range = max - min + 1;int* count = (int*)malloc(sizeof(int) * range);memset(count, 0, sizeof(int) * range);//计数for (int i = 0; i < n; i++){count[a[i] - min]++;}//排序int k = 0;for (int j = 0; j < range; j++){while (count[j]--){a[k++] = j + min;}}
}
//打印函数
Print(int* a, int n)
{for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf("\n");
}
int main()
{int a[] = { 6,1,6,7,9,6,4,5,6,1 };CountSort(a, sizeof(a) / sizeof(int));Print(a, sizeof(a) / sizeof(int));return 0;
}

计数排序的复杂度:

时间复杂度:O(N+range)

寻找最大值和最小值时,遍历一遍数组,时间复杂度是:O(N),由于待排数据的范围是range,排序时所耗费的时间复杂度是:O(range),所以最终的时间复杂度是:O(N+range)

如果知道N和range的大小,N大,就是O(N),range大,就是O(range)

空间复杂度:O(range)

额外开辟的空间个数是range,所以空间复杂度就是:O(range)

4.排序的复杂度和稳定性

总结如下:

 以上就是排序学习的全部内容了,到这,数据结构的学习就告一段落了,近期会停更一段时间,用来复习,后面将继续学习C++的知识,

未完待续。。。

http://www.yayakq.cn/news/317024/

相关文章:

  • 偷dede网站模板金融网站如何做设计方案
  • 成都网站创建服务专业建设
  • 网站建设和数据库维护网页设计素材 模板材料
  • 国外域名的网站河南省新闻发布会直播
  • 怎么做网站站内搜索杭州旅游团购网站建设
  • 帝国做的网站根目录保定网站建设公司大全
  • 聊城网站建设费用大庆做网站的
  • 机械门户网站建设特点饮食网站模板
  • wordpress将首页转成html湘潭网站优化公司
  • 个人免费网站天津优化加盟
  • 搭建wap网站在线制作app下载
  • 平台类网站建设价格表免费wordpress中文主题下载
  • 网站开发人员应该用什么浏览器手机编辑WordPress博客
  • 中国设计师联盟网站备案网站转入阿里云
  • 网站建设模板怎么做查网站服务器所在地
  • 西宁网站设计制作公司网站网页设计前言
  • 厦门旅游网站建设网站开发技术主管工作职责
  • php网站源码提升学历有哪几种途径
  • 湛江市seo网站设计联系方式贵州萝岗seo整站优化
  • 网站平台建设实训体会机械类网站用什么做背景
  • 做交易网站需要用到的软件企业做网站认证有哪些好处
  • 巨省网站网页设计页面尺寸
  • 做推文的网站的推荐网站打开慢 可以只换空间不换域名吗
  • 龙岗网站制作培训班眉山网站推广
  • 做网站推广的工作好吗wordpress 如何获得数据库数据
  • 做网站网站建设专业公司哪家好搜索网
  • 西安机场商务宾馆百度做网站网络推广软文是一种很好的推广方式
  • 个人如何做网站软件seo指的是什么意思
  • 做视频的素材什么网站好上海第五届世界进口博览会
  • 建什么样的网站好云主机搭建asp网站