Day4:排序算法(2/2)分而治之思想的应用

目录

一、回顾上次排序内容

 二、分治应用之二分查找

        1.背景:

        2.mid = l + (r-l)/2

        3.循环,非递归版本->二分查找实现代码

        4.递归版本->二分查找实现代码

三、分治应用之归并排序

        1.思想:

        2.步骤:

        3.代码实现:

四、分治应用之快速(分组)排序

        1.思想:

        2.步骤:(无需swap版)

基本要求:

图解示例:​编辑

        3.代码实现:

五、快排其他写法参照(swap):

一、回顾上次排序内容

    冒泡排序   每次冒出一个
    选择排序   每次选出一个放到合适位置
    插入排序   把左边一个元素看成一个有序数组

                                从第二个元素起把元素一个个的插入到有序数组中
    希尔排序   按步长 分组 组内作插入排序
    基数排序      数组下标天然有序  注意数组下标的限制:1.空间 2.正整数 3.不重复
    箱排序      分成若干个箱子,箱子内作其他排序

 二、分治应用之二分查找

        1.背景:

                有一个文件,文件中存有2G个电话号码。从中查找。
                1. 内存操作比文件操作效率高很多。
                2. 先排序

                假设有1-n的数字,最快猜多少次猜到这个数字。
                tips:结果会告知你
                    log2N

        2.mid = l + (r-l)/2

                注:若用mid=(l+r)/2容易越界(65535or larger)

        3.循环,非递归版本->二分查找实现代码

int BinarySearch(int arr[], int len,int posData)
{
	int left = 0,right=len-1;
	int mid = left + (right - left) / 2;//不推荐left+right 容易超出整数范围
	while (left <= right)
	{
		mid = left + (right - left) / 2;
		if (arr[mid] == posData)return mid;
		else if(arr[mid]>posData){right = mid - 1;}//更新搜索范围
		else { left = mid + 1; }
	}
	return -1;
}

        4.递归版本->二分查找实现代码

/*2.递归版本->二分查找*/
int BinarySearch(int arr[], int left,int right,int posData)
{
	if (left > right)return -1;//递归终止条件☆
	int mid = left + (right - left) / 2;
	if (arr[mid] == posData)return mid;
	else if (arr[mid] > posData) return BinarySearch(arr, left, mid - 1, posData);
	else return BinarySearch(arr, mid + 1, right, posData);
}

三、分治应用之归并排序

        1.思想:

                把两个有序数组合并成一个有序数组

        2.步骤:

            ①创建临时数组
            ② 一个个比较把两个有序数组中的元素逐个放到临时数组中    
            ③ 把剩下的放到临时数组中
            ④ 临时数组覆盖待排序数组    (注:memcpy效率更高

注意:执行顺序从下面的递归代码也可以看得出来,优先不断的执行第一个“分”,直到不能再分为止,然后退到上一层分,然后和1 1 2    ->2 2 4 个人感觉来说->有点像二叉树的DFS 

        3.代码实现:

void MergeSort(int* arr, int left, int right)
{
	if (left >= right)return;//相等也没有必要再去分了
	int mid = left + (right - left) / 2;
	
	MergeSort(arr, left, mid);//类似于dfs,一直在此分支上搜到底
	MergeSort(arr, mid + 1, right);
	Merge(arr, left, mid, right);
}
void Merge(int* arr, int left, int mid, int right)
{
	int* pArr = new int[right - left + 1];
	int k = 0;
	int i = left;//左区间的起始
	int j = mid + 1;//右区间的起始
	//1.依次去比较
	while (i <=mid&&j<=right)
	{
		if (arr[i] < arr[j])
			pArr[k++] = arr[i++];
		else
			pArr[k++] = arr[j++];//从小到大依次进行排序
	}
	//2.总会有剩下的,依次放入即可
	while (i <= mid)pArr[k++] = arr[i++];
	while (j <= right)pArr[k++] = arr[j++];
	//3.把临时数组的东西拷贝回去
	memcpy(arr+left, pArr,sizeof(int)*( right - left + 1));

	delete[]pArr;
	pArr = nullptr;
}

别忘记剩下的拷贝进去!!!

四、分治应用之快速(分组)排序

        1.思想:

                        把数据分成两组  左边的 比中间值小 右边的比中间值大

        2.步骤:(无需swap版)

基本要求:

        ①递归的终止条件!!

        ②一个基准点,两个移动指针(保证i的左侧均小于privot,j的右侧均大于privot,当两者相遇之时,privot的位置get√)

        ③本处采用覆盖的方式,对空间的开销更小,中间很巧妙,第一次j去覆盖i的时候,i的数据实际上已经保存在privot中,下一次是i是以一个大于privot的值去覆盖j,恰好方便j下一次开始循环,同时不用担心丢失数据,因为i去覆盖j的时候,上一次的j的值已经存在i上一次被覆盖的位置了。

        ④一定注意:谁覆盖谁!!->其实也很好记,下一次是j的循环,那必定是在i的循环中发现了比privot大的数字,所以赋值给j,刚好可以开始下一次的循环

图解示例:

 

 

 

 

 

 

 

        3.代码实现:

/*①快速排序*/
void quick_sort(int* a, int len)
{
	Qsort(a, 0, len - 1);
}
void Qsort(int* a, int left, int right)
{
	if (left >= right)return;  //注意递归终止条件

	int i = left;//左移动指针
	int j = right;//右移动指针
	int privot = a[left];//选取一个基准点
	while (i < j)
	{//要求i的左侧均要小于privot,j的右侧均要大于privot
		while (i < j && a[j] >= privot) j--;//当遇到第一个a[j]是比privot小的时候,覆盖
		a[i] = a[j];//->一定注意覆盖的顺序,j发现小的给i位置,刚好也能够方便下次i的循环
		while (i < j && a[i] <= privot)i++;
		a[j] = a[i];
	}//出循环表示i=j相遇了,此时更新相遇点->privot归位
	a[i] = privot;
	
	//递归
	Qsort(a, left, i - 1);//左边进行排序
	Qsort(a, i + 1, right);//右边进行排序
}

五、快排其他写法参照(swap): 

        这里的两个指针分别是index和i,i走在index前面。

int partition(int array[], int left, int right) 
{
	int pivot = left;
	int index = pivot + 1;
	for (int i = index; i <= right; i++)
	{
		if (array[i] < array[pivot]) 
		{
			Swap(array, i, index);
			index++;
		}
	}
	Swap(array, pivot, index - 1);
	return index - 1;
}
void quickSort(int array[], int left, int right) 
{
	if (left < right) 
	{
		int index = partition(array, left, right);
		quickSort(array, left, index - 1);
		quickSort(array, index + 1, right);
	}
}
void QuickSort(int array[], int arrayNum) 
{
	quickSort(array, 0, arrayNum - 1);
}

7.21测试上述两种快排的方式->第一种覆盖的方式会快于交换的方式!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Ocean__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值