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

龙采做网站要多少钱福建seo

龙采做网站要多少钱,福建seo,汝州市住房和城乡规划建设局网站,郑州专业seo推荐【八大经典排序算法】快速排序 一、概述二、思路实现2.1 hoare版本2.2 挖坑法2.3 前后指针版本 三、优化3.1 三数取中3.1.1 最终代码3.1.2 快速排序的特性总结 四、非递归实现快排 一、概述 说到快速排序就不得不提到它的创始人 hoare了。在20世纪50年代,计算机科学…

【八大经典排序算法】快速排序

  • 一、概述
  • 二、思路实现
    • 2.1 hoare版本
    • 2.2 挖坑法
    • 2.3 前后指针版本
  • 三、优化
    • 3.1 三数取中
      • 3.1.1 最终代码
      • 3.1.2 快速排序的特性总结
  • 四、非递归实现快排


在这里插入图片描述


一、概述

说到快速排序就不得不提到它的创始人 hoare了。在20世纪50年代,计算机科学家们开始研究如何对数据进行排序,以提高计算机程序的效率。当时,常用的排序算法包括冒泡排序、插入排序和选择排序等。

然而,这些算法的效率都相对较低,特别是在处理大量数据时。于是,人们开始寻找更快速的排序算法。Tony Hoare 在研究中发现了一种基于分治思想的排序方法,即快速排序。

二、思路实现

快速排序的思想是任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

代码如下:

// 假设按照升序对array数组中[left, right]区间中的元素进行排序
void QuickSort(int* a, int begin, int end)
{if (begin >= end)return;// 按照基准值对数组的 [left, right)区间中的元素进行划分int keyi = PartSort(a, begin, end);//分成[begin,keyi-1] keyi [keyi+1,end]// 递归排[left, div)QuickSort(a, begin, keyi - 1);// 递归排[div+1, right)QuickSort(a, keyi + 1, end);
}

上述为快速排序递归实现的主框架,发现与二叉树前序遍历规则非常像,接下来只需分析如何按照基准值来对区间中数据进行划分的方式即可。
待排序集合分割时,将区间按照基准值划分为左右两半部分的常见方式有以下3种。

2.1 hoare版本

思路

  1. 选择一个基准元素(key),可以是最左边也可以是最右边。
  2. 定义两个指针,一个指向数组的第一个元素(左指针),一个指向数组的最后一个元素(右指针)。(需要注意的是:若选择最左边的数据作为key,则需要right先走;若选择最右边的数据作为key,则需要left先走
  3. 移动左指针,直到找到一个大于等于基准元素(key)的元素;移动右指针,直到找到一个小于等于基准元素(key)的元素。之后交换交换左右指针所指向的元素。然后不断重复上述步骤直到左指针大于右指针
  4. 最后将基准元素与右指针所指向的元素交换位置,此时基准元素位于正确的位置。此时左边元素>=key,右边元素<=key。

Tips:博主在这里解释一下为什么“若选择最左边的数据作为key,则需要right先走;若选择最右边的数据作为key,则需要left先走”,后续其他方法同理。
① :左边作key,右边先走,保证了相遇位置的值小于key或就是key的位置。
②:右边作key,左边先走,保证了相遇位置的值大于key或就是key的位置。

以①为例,L和R相遇无非就两种情况:L遇R,R遇L。
情况一:L遇R。在R停下来后,L还在走。由于R先走,R停下来的位置一定小于Key。相遇位置为R停下来的位置,一定比key小。
情况二:R遇L。再相遇的这一轮,L就不动了,R在移动。相遇位置即为L的位置。而L的位置就是key的位置 or 已经交换过一些轮次了,此时相遇位置一定比key小。

【动画演示】:
在这里插入图片描述
代码如下:

 //[left, right]--采用左闭右闭
int PartSort(int* a, int left, int right)
{int keyi = left;while (left < right){//找到右边比key小的数while (left < right && a[right] <= a[keyi]){right--;}//找到左边比key大的数while (left < right && a[left] >= a[keyi]){left++;}Swap(&a[left], &a[right]);}Swap(&a[keyi], &a[left]);return left;
}void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}

2.2 挖坑法

思路

  1. .选出一个数据(一般是最左边或是最右边的)存放在key变量中,同时该数据位置形成一个坑。
  2. 还是左右指针left和right,left从左向右走,right从右向左走。(若在最左边挖坑,则需要R先走;若在最右边挖坑,则需要L先走)
  3. 移动右指针找到第一个比key小的数并填到坑位,此时右指针所在位置变成新的坑。然后移动左指针找到第一个比key大的数并填到坑位,此时左指针所在位置变成新的坑。然后和hoare版本一样,不断重复上述步骤即可

【动画演示】:
在这里插入图片描述
代码如下:

//挖坑法
int PartSort(int* a, int left, int right)
{int key = a[left];int hole = left;while (left < right){//找到右边比key小的值while (left < right && a[right] >= key){right--;}a[hole] = a[right];hole = right;//左边比key大的值while (left < right && a[left] <= key){left++;}a[hole] = a[left];hole = left;}a[hole] = key;return hole;
}void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}

2.3 前后指针版本

思路

  1. 选出一个key,一般是最左边或是最右边的。
  2. 起始时,prev指针指向序列开头,cur指针指向prev+1。
  3. 若cur指向的内容小于key,则prev先向后移动一位,然后交换prev和cur指针指向的内容,然后cur指针++;若cur指向的内容大于key,则cur指针直接++。如此进行下去,直到cur到达end位置,此时将key和++prev指针指向的内容交换即可。

【动画演示】:
在这里插入图片描述
代码如下:

//前后指针法
int PartSort(int* a, int left, int right)
{int keyi = left;int prev = left;int cur = left + 1;while (cur <= right){if (a[cur] < a[keyi] && ++prev != cur){Swap(&a[prev], &a[cur]);}cur++;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}

三、优化

虽然已经可以解决问题了,但还有一个问题:
当选取的key每次都是中位数时,效率最好,时间复杂度为O(N*logN);但当数组有序时变成最坏,时间复杂度变为O(N^2)!
对于上述情况,这里有两种优化方式:

  1. 三数取中法选key
  2. 递归到小的子区间时,可以考虑使用插入排序

3.1 三数取中

这里博主给出一直最简单的方法:

int GetMidIndix(int* a, int left, int right)
{int mid = left + (right - left) / 2;if (a[left] < a[mid]){if (a[mid] < a[right])return mid;else if (a[mid] > a[right])return right;elsereturn left;}else//a[left]>=a[mid]{if (a[mid] > a[right])return mid;else if (a[mid] < a[right])return right;elsereturn left;}
}

3.1.1 最终代码

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}int GetMidIndix(int* a, int left, int right)
{int mid = left + (right - left) / 2;if (a[left] < a[mid]){if (a[mid] < a[right])return mid;else if (a[mid] > a[right])return right;elsereturn left;}else//a[left]>=a[mid]{if (a[mid] > a[right])return mid;else if (a[mid] < a[right])return right;elsereturn left;}
}// hoare
// [left, right]
//int PartSort(int* a, int left, int right)
//{
//	int midi = GetMidIndix(a, left, right);
//	Swap(&a[left], &a[midi]);
//
//	int keyi = left;
//	while (left < right)
//	{
//		//找到右边比key小的数
//		while (left < right && a[right] <= a[keyi])
//		{
//			right--;
//		}
//
//		//找到左边比key大的数
//		while (left < right && a[left] >= a[keyi])
//		{
//			left++;
//		}
//		Swap(&a[left], &a[right]);
//	}
//	Swap(&a[keyi], &a[left]);
//	return left;
//}//挖坑法
//int PartSort(int* a, int left, int right)
//{
//	int midi = GetMidIndix(a, left, right);
//	Swap(&a[left], &a[midi]);
//
//	int key = a[left];
//	int hole = left;
//	while (left < right)
//	{
//		//找到右边比key小的值
//		while (left < right && a[right] >= key)
//		{
//			right--;
//		}
//		a[hole] = a[right];
//		hole = right;
//
//		//左边比key大的值
//		while (left < right && a[left] <= key)
//		{
//			left++;
//		}
//		a[hole] = a[left];
//		hole = left;
//	}
//	a[hole] = key;
//	return hole;
//}//前后指针法
int PartSort(int* a, int left, int right)
{int midi = GetMidIndix(a, left, right);Swap(&a[left], &a[midi]);int keyi = left;int prev = left;int cur = left + 1;while (cur <= right){if (a[cur] < a[keyi] && ++prev != cur){Swap(&a[prev], &a[cur]);}cur++;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end)return;int keyi = PartSort(a, begin, end);//分成[begin,keyi-1] keyi [keyi+1,end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}

3.1.2 快速排序的特性总结

  1. 时间复杂度:O(N*logN)

在这里插入图片描述

  1. 空间复杂度:O(logN)
  2. 稳定性:不稳定

四、非递归实现快排

思路:

  1. 定义一个栈,然后将待排序的数组的起始索引和结束索引入栈。
  2. 通过前面将的三种分割区间的方法将数组的起始索引和结束索引之间的元素分成两部分,左边部分小于等于基准元素,右边部分大于等于基准元素。
  3. 由于非递归实现时,我们是通过从栈中两两取出维护待排序数组的下标,所以接下来就是如果左边部分的长度大于1,则将左边部分的起始索引和结束索引入栈;如果右边部分的长度大于1,则将右边部分的起始索引和结束索引入栈。最后循环此操作,直到栈为空。

代码如下:

//前后指针法
int PartSort(int* a, int left, int right)
{int midi = GetMidIndix(a, left, right);Swap(&a[left], &a[midi]);int keyi = left;int prev = left;int cur = left + 1;while (cur <= right){if (a[cur] < a[keyi] && ++prev != cur){Swap(&a[prev], &a[cur]);}cur++;}Swap(&a[prev], &a[keyi]);keyi = prev;return keyi;
}//快排非递归
void QuickSortNonR(int* a, int begin, int end)
{ST st;STInit(&st);STPush(&st, end);STPush(&st, begin);while (!STEmpty(&st)){int left = STTop(&st);STPop(&st);int right = STTop(&st);STPop(&st);int keyi = PartSort(a, left, right);//[left,keyi-1] keyi [keyi+1,right]if (keyi + 1 < right){STPush(&st, right);STPush(&st, keyi + 1);}if (keyi - 1 > left){STPush(&st, keyi - 1);STPush(&st, left);}}STDestroy(&st);
}

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

http://www.yidumall.com/news/40267.html

相关文章:

  • 天津网站制作专业国内疫情最新消息
  • 金湖网站建设公司快速建站
  • 有那些专门做外贸的网站呀宁波网站推广运营公司
  • 怎么做好一个网站深圳网络推广网站推广
  • h5 小米网站模板今日热榜
  • 贵阳哪家网站做优化排名最好营销怎么做
  • 西安网站排名优化培训爱战网关键词
  • 做网站的技术盏智能建站平台
  • 深圳建站公司告诉你十个建站步骤长沙百度推广公司电话
  • 凡科网站怎么做外链网站推广工具有哪些
  • 网站做程序需要多久非国产手机浏览器
  • 电脑版网站转手机版怎么做seo软件推广哪个好
  • 高职高专网站建设与维护seo优化自动点击软件
  • 做下载网站好不好做新网站多久会被百度收录
  • 如何做网站结构优化关于进一步优化当前疫情防控措施
  • 网站开发可退税济南市新闻最新消息
  • 硅云买域名做网站郑州seo服务
  • java学完后可以做网站吗世界足球世界排名
  • 北京最新防疫信息黑帽seo培训
  • 网站关键词优化的价格网站建设方案书 模板
  • 海南平台网站建设企业电销系统
  • 做企业网站的公司有哪些小程序开发需要多少钱
  • p2p网站的建设品牌营销推广要怎么做
  • 详情页尺寸免费seo诊断
  • 可以自己做网站吗昆山网站建设公司
  • 有了域名和空间怎么做网站内容google推广 的效果
  • 网站建设手机端管网企业品牌策划
  • 龙岗网站制作资讯志鸿优化设计电子版
  • 河北省建设网站的网站首页seo关键词平台
  • 做海报素材网站百度经验app