🫥acwing基础算法笔记
<丘比特,大梦想>
那些不能杀死我们的,必将使我们变得强大 ——尼采
😏算法目录😏
1.快速排序
2.归并排序
3.二分查找
(1)整数二分
(2)浮点数二分
🐻前言
本篇文章主要针对在acwing算法课中的一些困惑和重要思路进行整理,从而便于复习提升。
1.快速排序
快速排序是一个比较经典的算法其主要是利用分冶的思想对总区间进行无限细分并对每个小区间进行调整,从而达到有序的目的。
具体实现及分析:
(1)算法基本结构
函数名称以及参数对象:
**名称:**函数接口的名字尽量与quick sort有关联缩写也好,要让人一读就能明白函数接口的意义
**参数:**因为这里来主要对数进行排序来演示所以参数就直接设置为整型指针,和左右边界下标.因为是传址调用直接更改数组并不需要返回什么参数所以就设为void
void my_qsort(int* arr,int l,int r)
算法主要模式:
主要实现方式是递归,值得注意的是在递归的时候要提前设好跳出条件,即将区间细分完或者子区间待细分序列只剩下一个数的时候就要进行跳出了,如若不然则会死递归导致栈溢出。所以综上我们递归的基准条件就已经确定了当递归传入区间中只有一个或0个的时候跳出
。
简单来说就是当数组只有一个数或压根就是空的时候不用对数组进行排序了,因为他本来就是有序的
if(l >= r)
{
return;//因为返回值是空类型所以并不需要返回什么具体的值
}
递归进行的主要操作:
递归基准条件已经确定了,那么就应该确定一下具体操作了,我们先从数据量较小的看起:
然后咱们再把数据增加一下:
仅仅是这点数据还是无法体现分治法的优点,下面我们加大亿点难度:
1.选取基准值定义相关变量对应的值以及移动左右边界的临时变量:
一般选取最左边,最右边,以及中间值
int i = l - 1;//一开始要将临时变量指向数组外边,因为后边要利用do—while语句进行指向元素与基准值进行比较
int j = r + 1;//比较后确定了关系进行交换。
int x = arr[l + r >> 1]//这里选取中间值作为基准
2.区分区间不符合区间关系的进行交换
while(i < j)//当指向左右的变量重合或者是交错的时候,就要跳出
{
//确定指向左边的是不是小于基准值
do
{
i++;//这便于理解上边的l - 1的操作了,因为上来就要移动。
}while(arr[i] < x);
//确定是不是大于基准值
do
{
j++;
}while(arr[j] > x);
//判断是否未相遇或者是错过
if(i < j)//因为前文已经进行了移动所以要对while条件在进行判断
{
//交换
swap(arr[i],arr[j]);//c++库中特有的函数
}
}
3.确定递归传入数据来执行递归操作
因为分治法是对区间不断细分的递归手段所以要确定好传入数据,以及对应递归区间的界限,因为是不断分为两块,所以要对所剩的两个区间分别进行细分所以要进行两次递归。
my_qsort(arr,l,j)//这里的j代表第一块区间的边界
my_qsort(arr,j+ 1,j)//这里的j+1代表右边界的起点
2.归并排序
其实归并排序的思想与上边的思想如出一辙,也是分治的思想将数组分成两个区间,无限细分成两个区间只剩下一个的时候对两个序列进行比较合并到临时数组中,然后在最后将数据一点一点读入原来数组。
//临时数组尽量开大点
const int N = 100010;
int tem[N] = {0};
void mer_sort(int * p,int l,int r)
{
//确定基准值,中间
mid = l + r >> 1;
//进行细分区间
//对从中间分开的区间分别进行细分
mer_sort(p,l,mid);
mer_sort(p,mid + 1,r);
//设定移动的临时变量,以及重排列的变量
int i = l;//每个区间的起始
int j = mid + 1;
int k = 0;//重排变量
//开始比较存放,这时可以将两个区间看作两个单独的数组,所以这里的合并的条件就是边界问题了
while(i <= mid && j <= r)
{
if(p[i] > p[j])
{
tem[k++] = p[j++];
}
else
{
tem[k++] = p[i++];
}
}
//因为有可能有剩的所以要进行边界判断,然后进行拼接
while(i <= mid)
{
tem[k++] = p[i++];
}
while(j <= r)
{
tem[k++] = p[j++];
}
//将tem的数从当前递归的左边界进行拼接
for(i = l,j = 0;i <= r;i++,j++)
{
//进行读入
p[i] = tem[j];
}
}
2.二分查找
二分重要的是找到那个分区的条件,即答案所处区间和答案不在的区间的分界。其实二分说简单也简单,说不简单,有时候你还真想不到。大家可能都做过猜数字这个小游戏,或者是数字炸弹,一般都是用二分法来猜的,因为这样能一下排除剩下的一半。
但是在编程中大家有时候根本不敢用,因为动不动就数组越界了。让人很崩溃。但是,今天我两个模板便能解决你的苦恼让你大呼过瘾。
例如:
这题就是利用二分把左右边界找到:
如: 1,2,2,3,3,4
如果我要查找2的话那么就要返回1 ,2
如果4的话则5,5.
如果没有的话-1,-1
模板:
//判断是否符合某种能够缩小答案空间的条件
bool check(int x)……
int half_sort(int l,int r)//适合进行极致向右进行右边界查找
{
while(l < r)//当两个重合的时候跳出
{
int mid = l + r >> 1;
if(chaeck(x))//注意这是你自己画图判断答案区间的条件
{
r = mid;
}
else
{
l = mid + 1;
}
}
return l;//因为会重合所以返回那个都一样
}
int half_sort1(int l,int r)
{
while(l < r)//当两个重合的时候跳出
{
int mid = l + r >> 1;
if(chaeck(x))//注意这是你自己画图判断答案区间的条件
{
l = mid;
}
else
{
r = mid - 1;
}
}
return l;//因为会重合所以返回那个都一样
}
注意:其中的if条件根据自己理解进行调整,即预期区间缩小来确定
二分虽好,可不要贪杯。
结语
愿诸君可以未来乘风破浪,如果您对以上内容感兴趣的话请三连支持一下,您的三连是我莫大的动力