IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 排序 | 快速排序 -> 正文阅读

[游戏开发]排序 | 快速排序

思想

每一次划分,使左边均小于基准,右边均大于,但是无序,然后再将左右边各划分一次,这样划分下去,直到分解数组大小为1,划分停止,此时已经有序.

划分函数

快排中划分函数时必不可少的,他的作用是确定一个基准,然后以此基准进行划分,划分的方式有很多种,最常用的是双指针在边界处进行遍历,右指针找小于基准的,左指针找大于基准的,然后交换,直到左右指针重合,再把基准放到最终指针位置,这样基准的左边均小,右边均大了.

双指针指向最左和最右的划分函数
int Partition(int* ar, int left, int right)
{
	int tmp = ar[left];
	while (left < right)
	{
		while (right > left && ar[right] > tmp) right--;
		ar[left] = ar[right];
		while (right > left && ar[left] <= tmp) left++;
		ar[right] = ar[left];
	}
	ar[left] = tmp;
	return left;
}
单向逼近的划分函数

i和j中间的为大于基准的数,向右扫描,当找到比基准小的数,就i和j中间的数交换,此方法可以用作单链表的快速排序

int Partition1(int* ar, int left, int right)
{
	int i = left-1;
	int j = left;
	while (j <= right)
	{
		while (j<=right && ar[j] > ar[left]) j++;
		if (j > right) break;
		swap(ar[++i], ar[j++]);
		/*if (ar[j] <= ar[left])
		{
			++i;
			swap(ar[i], ar[j]);
		}
		++j;*/
	}
	swap(ar[i], ar[left]);
	return i;
}

排序函数

递归版本

void Qsort(int* ar, int left,int right)
{
	if (right > left)
	{
		int pos = Partition1(ar, left, right);
		Qsort(ar, left, pos - 1);
		Qsort(ar, pos + 1, right);
	}
}

非递归版本:
非递归的实现要利用介质来储存要进行划分的区间,可以用栈,队列,对

void Qsort(int* ar, int size)
{
	stack<int> st;
	st.push(size - 1);
	st.push(0);
	
	while (!st.empty())
	{
		int left = st.top(); st.pop();
		int right = st.top(); st.pop();
		int pos = Partition(ar, left, right);
		if (pos > left)
		{
			st.push(pos - 1);
			st.push(left);
		}
		if (right > pos)
		{
			st.push(right);
			st.push(pos + 1);
			
		}
	}
}

BFPRT算法

算法思想:
对于求数组中第k小的元素的问题,我们已经有很好的常规算法了,这个算法在最好的情况下时间复杂度是O(n),但在最坏的情况下是O(n^2)的,其实bfprt算法就是在这个基础上改进的。

常规解法:
我们随机在数组中选择一个数作为划分值(number),然后进行快排的partation过程(将小于number的数放到数组左边,等于number的数放到数组中间,大于number的数放到数组右边),然后判断k与等于number区域的相对关系,如果k正好在等于number区域,那么数组第k小的数就是number,如果k在等于number区域的左边,那么我们递归对左边再进行上述过程,如果k在等于number区域的右边,那我们递归对右边再进行上述过程。

对于常规解法,我们分析一下它的时间复杂度:

递归函数复杂度计算:

T(N)=aT(N/b)+o(N^d);
当log(b,a)>d时 复杂度为O(N^log(b,a));
当log(b,a)=d时 复杂度为O(N^d
log(2,N));
当log(b,a)<d时 复杂度为O(N^d);
N为样本数据个数 即数组中元素的个数。
N/b为将这N个数划分为更小的部分,每个部分的样本数据个数,一般为均分,那么b等于2。
a为划分为多个部分后,小部分执行的次数。
d为递归函数调用完成后剩下的操作的时间复杂度。

对于最好的情况:每次所选的number正好在数组的正中间,那么上式中a等于1,b等于2,对于partation过程,时间复杂度是O(n),所以d等于1。所以T(N)= T(N/2)+ O(N),此时 log( 2 , 1 ) < 1,故时间复杂度为O(N)。

对于最坏情况:每次所选的number正好在数组最边上,那么时间复杂度为O(N ^ 2).

bfprt算法就是在这个number上做文章,bfprt算法能够保证每次所选的number在数组的中间位置,那么时间复杂度就是O(N)。

两个重要函数:取中间值函数,寻找第k小函数
中位数的寻找又得利用寻找第k小函数来寻找
第k小函数利用中位数获取最佳划分点,相互调用的递归函数,有点难以理解

void Sort(int* ar, int left, int right)//bubble
{
	//sort
	for (int i = left, n=0 ;i < right; i++,n++)
	{
		for (int j = left; j < right-n; j++)
		{
			if (ar[j] > ar[j + 1])
			{
				swap(&ar[j], &ar[j + 1]);
			}
		}
	}
}

int GetMidIndex(int* ar, int left, int right)
{
	int left1 = left;
	int count = (right - left + 1) / 5;//记录应该循环几次
	int res = (right - left + 1) % 5;
	if (right-left+1<=5)
	{
		Sort(ar, left, right);
		return (right + left) / 2;
	}
	int n = left;

	for(int i=0;i<count;i++)
	{
		Sort(ar, left, left + 4);
		swap(&ar[n++], &ar[left + 2]);
		left += 5;
	}
	if (res > 0)
	{
		Sort(ar, right - res + 1, right);//0 1 2 3 4 5 6 7 8 9 10
		swap(&ar[n], &ar[right - res / 2]);//right - res/2
	}
	else count--;
	return (BFPRT(ar, left1, left1 + count, (count / 2)+1));
	
	
}
int Partition(int* ar, int left,int right, int i)//i是基准坐标
{

	while (right > left)
	{
		while (left < right && ar[right] > ar[i]) right--;
		while (left < right && ar[left] <= ar[i]) left++;
		swap(&ar[left], &ar[right]);
	}
	swap(&ar[left], &ar[i]);
	return left;

}
int BFPRT(int* ar,int left,int right,int k)//第k大就是第size-k小
{
	int mid_index=GetMidIndex(ar, left, right);
	int part_index=Partition(ar, left, right, mid_index);
	int num = part_index - left+1;
	if (num == k)
	{
		return part_index;
	}
	else if (num > k)
	{
		return BFPRT(ar, left, part_index-1, k);
	}
	else
	{
		return BFPRT(ar, part_index+1, right, k - num);
	}
}
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 01:31:05  更:2022-02-19 01:31:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 17:43:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码