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

泰安手机网站建设搭建一个网站平台需要多少钱

泰安手机网站建设,搭建一个网站平台需要多少钱,年终总结ppt模板免费下载网站,职业生涯规划大赛活动总结目录 1.快速排序的核心思想2.快速排序的实现方式2.1 递归版本2.1 hoare版本2.2 lomuto版本 2.2 非递归版本(仅了解即可) 3.以上实现的快排方式的缺陷4.快排的优化4.1 基准值优化4.3 优化后的测试4.2 基准值分化区间优化 1.快速排序的核心思想 快速排序是…

目录

  • 1.快速排序的核心思想
  • 2.快速排序的实现方式
    • 2.1 递归版本
      • 2.1 hoare版本
      • 2.2 lomuto版本
    • 2.2 非递归版本(仅了解即可)
  • 3.以上实现的快排方式的缺陷
  • 4.快排的优化
    • 4.1 基准值优化
    • 4.3 优化后的测试
    • 4.2 基准值分化区间优化

1.快速排序的核心思想

快速排序是排序算法中较为优异的一种,它的核心思想就是:选取一个数据作为基准值,然后遍历需要排序的数据,使这个基准值放到它该放的位置,再对剩下的子区间进行递归,最后所有的数据都会放到它该放的位置,就完成了排序

2.快速排序的实现方式

这里我们先默认选取每一次递归区间的最左边的元素作为基准值,当然这种选取方式其实在某些特殊的数据存在很大的问题(待会再讨论)

2.1 递归版本

2.1 hoare版本

a.思路:给定left指针(代表下标)和right指针,分别从数据的左边和右边进行遍历,left指针从左往右找大,right指针从右往左找小,这里的比较是与基准值

b.画图展示:
注意:这里可以先让left指针先走一步,让比较的次数减少,一定程度上优化了一点点

在这里插入图片描述
在这里插入图片描述
从画图的方式可知:>思路(续):left指针和right指针找的过程当left比right大则停止,此时right指向的位置就是keyi该放的地方,交换即可

这里的递归左右区间的意思是:交换完keyi和right以后,该轮的keyi已经排序了,只要再对它的左右两段区间重复该一操作即可(递归),如图:
在这里插入图片描述
跳出循环的right会作为基准值返回,有了基准值就能得到左右区间的范围了

c. 代码实现:
这里将找基准值的方法和主体逻辑进行分离:

void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}//找基准值的方式
int  re_QuickSort(int* arr, int left, int right)
{int keyi = left;++left;//这里left与right取等也要进入循环//如果它们相遇时指向的值比基准值大,不进入循环指向的元素就没有放到该放的位置while (left <= right){//right从右往左找比基准值小的数// left从左往右找比基准值大的数while (left <= right && arr[right] > arr[keyi]){right--;}while (left <= right && arr[left] < arr[keyi]){left++;}if (left <= right){//让left和right继续走Swap(&arr[right--], &arr[left++]);}}//在right下标和left下标交换后,left和right都会移动//可能在移动过程就不满足left <=right//所以让right与keyi进行交换应在循环外Swap(&arr[right], &arr[keyi]);return right;
}//主体
void reQuickSort(int* arr, int left, int right)
{//保证区间是有效的if (left >= right){return;}int keyi = re_QuickSort(arr, left, right);//将区间分为[left,keyi-1]   [keyi+1,right]reQuickSort(arr, left, keyi - 1);reQuickSort(arr, keyi + 1, right);}

另:
在上面我们让left先走了一步,但是如果不让left先走一步,应该怎样处理呢?
如图:
在这里插入图片描述
在这里插入图片描述
注意:这里是为了画图方便在交换位置少了&操作符,它只是一段“伪代码”

在这里插入图片描述
此时如果再使用原来找keyi的方法只会让那两元素不断进行交换造成死递归,通过该图可以发现,这里只要right < keyi,此时的right在该段区间就是属于非法的,所以只需在跳出循环的时候判断两者即可,如果非法返回keyi

代码实现:

//left不++的基准值选取方法
int noneleft_Quick_sort(int* arr, int left, int right)
{int keyi = left;while (left <= right){//right找小,left找大while (left <= right && arr[right] > arr[keyi]){right--;}while (left <= right && arr[left] < arr[keyi]){left++;}if (left <= right){Swap(&arr[left++], &arr[right--]);}}if (right < keyi){return keyi;}else{//尽量进行有效交换if (right != keyi){Swap(&arr[keyi], &arr[right]);}return right;}}

笔者建议:
从这个例子就可以看出,当我们想要改动代码的时候会造成不可预料的结果,如果要进行改动,需要弥补相应的措施,动手画图 + 调试会渐渐让你变得富有经验,耐心一点儿,问题总会解决的

2.2 lomuto版本

前言:该一实现方式又名双指针法,在初次接触的时候会感觉非常奇妙很难想,但是只要理解了背后的算法设计,就觉得还好

a.思路:
1.定义两个指针prev(left位置),pcur(left+1位置)
2.pcur在前面探路,只要pcur下标的元素比keyi小,就先让prev++,再与pcur++交换;如果比keyi大,直接++
3.跳出循环的时候,prev此时的指向就是基准值该待的位置,与keyi交换

b.代码实现:

//双指针版本
int dp_QuickSort(int* arr, int left, int right)
{int keyi = left;int prev = left, pcur = prev + 1;while (pcur <= right){//pcur探路,找到比基准值小的数,先++prev然后与pcur交换//如果没有找到比基准值小的数,pcur++//pcur越界了,此时prev指向的就是keyi该待的位置if (arr[pcur] < arr[keyi] && ++prev != pcur){Swap(&arr[prev], &arr[pcur]);}++pcur;}Swap(&arr[prev], &arr[keyi]);return prev;
}void dpQuickSort(int* arr, int left, int right)
{if (left >= right){return;}int keyi = dp_QuickSort(arr, left, right);dpQuickSort(arr, left, keyi - 1);dpQuickSort(arr, keyi + 1, right);}

c.算法思想:
pcur对整个数组进行遍历,需要指向right(也是有效区间值)才结束,这里本质上其实就是对数组中进行三区间分化:

在这里插入图片描述
这里可以看出:从left~prev指向的区域都是≤keyi(5)的:

在这里插入图片描述

2.2 非递归版本(仅了解即可)

在非递归版本的快排实现中,我们需要借助一种数据结构:栈,主要的思路就是将区间放入栈中,并不断入栈出栈

代码实现:

void QuickSortNonR(int* arr, int left, int right)
{ST stack;STInit(&stack);//先将left和right入栈//注意栈的顺序:先进后出StackPush(&stack,right);StackPush(&stack,left);while (!StackEmpty(&stack)){int begin = StackTop(&stack);StackPop(&stack);int end = StackTop(&stack);StackPop(&stack);int prev = begin, pcur = begin + 1;int keyi = begin;while (pcur <= end){//pcur探路,找到比基准值小的数,先++prev然后与pcur交换//如果没有找到比基准值小的数,pcur++//pcur越界了,此时prev指向的就是keyi该待的位置if (arr[pcur] < arr[keyi] && ++prev != pcur){Swap(&arr[prev], &arr[pcur]);}++pcur;}Swap(&arr[prev], &arr[keyi]);keyi =  prev;//区间:[begin,keyi-1] [keyi+1,end]if (keyi + 1 < end){StackPush(&stack,end);StackPush(&stack, keyi+1);}if (begin < keyi - 1){StackPush(&stack, keyi - 1);StackPush(&stack,begin);}}STDestroy(&stack);
}

3.以上实现的快排方式的缺陷

上述快排的实现,我们都直接选取了最左边的元素为基准值,从各个图进行分析就可以看出快速排序一般来说就是一颗递归树,递归树的时间复杂度为O(n*logn),但是碰到刚好完全有序的数据或者存有大量相同数据时,快排就会退化

本身就有序的情况:
这里以双指针版进行演示:

在这里插入图片描述
可以看到这里的快排就不是一颗递归树了,如果当存在大量数据时,效率就变得非常低,所以对于基准值的选取需要更进

4.快排的优化

优化大致就是对提到的两种情况进行相应的处理,尽量使得快排为一颗递归树

4.1 基准值优化

1.三数取中
要想让递归的区间从中间开始,就需要选取的基准值处在数据中不大也不小的状态,这样选取的基准值在第一轮时就会被放到中间,进而就大大缩减了递归的次数

代码实现:

//三数取中 -- 三个数中取中位数,基准值的选择尽量为数组中不大不小的元素
//如果只让基准值处于较大/较小的元素,递归的次数会增多,时间复杂度退化至o(n^2)
int midthree(int* arr, int left, int mid, int right)
{//0^1=1^0=1,0^0=1^1=0if ((arr[left] < arr[mid]) ^ (arr[left] < arr[right])){//说明:ar[left]不大也不小return left;}else if ((arr[mid] < arr[left]) ^ (arr[mid] < arr[right])){//说明:arr[mid]不大也不小return mid;}else{//说明:arr[right]不大也不小return right;}
}

优化后的快排——hoare版本

//三数取中版本——针对有序的数组做了优化,但是处理不了含有大量重复数据的情况
int  mid_QuickSort(int* arr, int left, int right)
{int med = midthree(arr, left, (left + right) / 2, right);//让中位数与最左边元素交换Swap(&arr[med], &arr[left]);int keyi = left;++left;//这里left与right取等也要进入循环//如果它们相遇时指向的值比基准值大,不进入循环指向的元素就没有放到该放的位置while (left <= right){//right从右往左找比基准值小的数// left从左往右找比基准值大的数while (left <= right && arr[right] > arr[keyi]){right--;}while (left <= right && arr[left] < arr[keyi]){left++;}if (left <= right){Swap(&arr[right--], &arr[left++]);}}//在right下标和left下标交换后,left和right都会移动//可能在移动过程就不满足left <=right//所以让right与keyi进行交换应在循环外Swap(&arr[right], &arr[keyi]);return right;
}void midQuickSort(int* arr, int left, int right)
{if (left >= right){return;}int keyi = mid_QuickSort(arr, left, right);midQuickSort(arr, left, keyi - 1);midQuickSort(arr, keyi + 1, right);}

4.3 优化后的测试

这里以一道排序算法题作为测试:数组排序

优化前:
在这里插入图片描述

优化后:
在这里插入图片描述
2.随机数作基准值
这里还提供了另外一种方法作基准值:使用随机数,该数的范围在left~right之间,这种方式在算法导论中有进行严格的数学推到证明,有兴趣的读者可以自行了解

代码实现:

//设置种子
srand((unsigned int)time(NULL));
int keyi = arr[rand() % (right - left + 1) + left];

4.2 基准值分化区间优化

前言:当数组中含有大量相同数据时,我们实现的递归还是会退化,有了前面双指针算法的思想,可以衍生出另一个算法:三指针;双指针算法只是将区域分化成两部分:≤keyi、>keyi,但是如果再进一步划分区域:将=keyi的区域单独划分,那么快排的算法效率就会得到显著上升:

算法思想:
pleft:标记左区间,处理最后一个<keyi的位置
pright:标记右区间,处理第一个>keyi的位置
pcur:遍历整个数组

如图:
在这里插入图片描述

处理时的行为:
这里大于keyi时的情况已经在双指针讨论过了,这里照搬即可,等于keyi时,直接++即可,就剩下小于keyi时,我们用pright处理,这里只需先–pright,再与pcur交换,但是注意:pcur此时还不能动,因为–pright指向的元素还是不确定的,需要pcur进行判断,最后遍历完以后只需递归<keyi区间和>keyi区间,这种实现对于大量相同数据做了很好的处理

代码实现:

void tpQuickSort(int* arr, int left, int right)
{if (left >= right){return;}//使用pleft、pright进行三路划分//采用随机取keyi的方式srand((unsigned int)time(NULL));int keyi = arr[rand() % (right - left + 1) + left];//int keyi = arr[left];int pleft = left - 1, pright = right + 1;int pcur = left;while (pcur < pright){if (arr[pcur] < keyi){Swap(&arr[++pleft], &arr[pcur++]);}else if (arr[pcur] > keyi){Swap(&arr[--pright], &arr[pcur]);}else{pcur++;}}//(left,pleft)   (pleft+1,pright-1)   (pright,right)// < keyi              ==keyi                 >keyitpQuickSort(arr, left, pleft);tpQuickSort(arr, pright, right);
}
http://www.dtcms.com/wzjs/100159.html

相关文章:

  • 凡科做网站不要钱兰州网站seo诊断
  • 网站制作的软件重庆自动seo
  • 提供网站制作公司报价网站市场推广
  • 怎么注册自己的微网站外贸平台
  • 网站建设两个方面网站页面禁止访问
  • 财务咨询网站模板营销课程培训哪个机构好
  • 怎样做自己的公司网站百度官网登录
  • 郑州自建网站网络促销
  • 哪种nas可以做网站服务器网络营销公司是做什么的
  • 镇江做网站多少钱网店怎么推广和宣传
  • 西安市建设建委网站武汉网络关键词排名
  • 饭店餐厅网站建设推广联系方式
  • 钟祥网站建设如何制作简单的网页链接
  • 郑州医疗网站建设网络推广员是干嘛的
  • 做网站需准备些什么问题佣金高的推广平台
  • 小程序游戏排行榜2023兰州网络推广优化服务
  • 成人网站vps北京搜索引擎优化主管
  • 西安php网站制作百度有几种推广方式
  • wordpress怎么新建子域名廊坊百度关键词优化怎么做
  • 做网站需要哪些人才凌哥seo技术博客
  • 爱站网权重查询网址之家
  • 网站制作 沈阳网络推广服务费
  • 杜桥做网站哪家好网站百度收录突然消失了
  • 网站关键词搜索优化怎么做全网自媒体平台大全
  • 培训网站开发公司无货源网店怎么开
  • 雪域什么网站是做电影的怎么注册网址
  • dede 网站地图模板htm河南今日头条最新消息
  • 做网站需要提供哪些资料站长工具站长
  • 平台网站建设ppt模板下载广州网站seo
  • 在电脑上怎么做网站网上网络推广