⩕ 排序
〇 快速排序
1、原理 ( 升序 )
先在区间中寻找一基准元素,将区间中元素分别与之比较,并进行处理
以保证比基准元素小的在基准元素之前,比基准元素大的在基准元素之后
处理完毕后,数组即排序完成
2、核心模板( 升序 )
void quick_sort( int q[] , int l , int r)
{if(l > r) return; //当左右端点相遇,结束循环int x = q[ l + r >> 1 ]; //定义基准元素,用于与左右端点指向的int i = l - 1 , j = r + 1; //定义左右端指针,分别有两端至中间移动while(i < j) //左右端指针未相遇时,继续循环{do i++;while(q[i] < x); //若i所指向的元素小于基准元素,则继续循环do j--;while(q[j] > x); //若j所指向的元素大于基准元素,则继续循环if(i < j) swap( q[i] , q[j] ); //上述循环结束后,此时i所指元素大于基准元素,j所指元素小于基准元素,交换二者}quick_sort( q , l , j ); //递归重复上述过程quick_sort( q , j + 1 , r );
}
〇 归并排序
1、核心模板 ( 升序 )
void merge_sort( int q[] , int l , int r)
{if(l > r) return; //中断条件:左右端相遇int mid = l + r >> 1; //取中点merge_sort( q , l , mid ),merge_sort( q , mid + 1 , r); //划分区间int k = 0; //定义辅助指针,指向辅助数组中元素int i = l , j = mid + 1; //定义端点指针,从划分的区间的左端点开始向右循环 while(i <= mid && j <= r) //中断条件:区间循环完毕if(q[i] <= q[j]) tmp[k++] = q[i++]; //比较i,j所指元素,将符合单调性的元素输入辅助数组else tmp[k++] = q[j++];while(i <= mid) tmp[k++] = q[i++]; //循环区间while(j <= r) tmp[k++] = q[j++];for(i = l,k = 0 ; i <= r ; i++,k++) //将排序完毕的辅组数组赋给需要排序的数组tmp[k] = q[i]
}
⩕ 二分
1、应用
给定一序列,搜索符合条件的元素
2、原理
先取区间中点,将区间划分,再检查该中点所对元素是否符合搜索条件,再依据检查结果对半缩小区间,即缩小搜索范围
3、核心模板
int bsearch_l(int l,int r)
{while(l < r) //中断条件:l,r相遇{int mid = l + r >> 1; //取中点if(check(mid)) r = mid; //check(mid)用于判断mid是否符合搜索条件else l = mid + 1; //是则去除右区间,保留左区间,否则去除左区间,保留右区间}return l; //返回l,r相遇位置,即搜索结果
}
int bsearch_r(int l,int r)
{while(l < r){int mid = l + r + 1 >> 1;if(check(mid)) l = mid; //check(mid)用于判断mid是否符合搜索条件else r = mid - 1; //是则去除左区间,保留右区间,否则去除右区间,保留左区间}return l;
}
⩕ 高精度计算
〇 高精度数的储存
高精度数输入时常用一字符数组进行接收,而后将每一位上的字符按由低位到高位的顺序转化为数字,而后存进一`int`行数组中
该int型数组常采用变长数组,即`vector<int>`进行定义
1、核心模板
string s1,s2; //定义接收高精度数的字符数组
vector<int> A,B; //定义储存高精度数的数组
cin >> s1 >> s2; //读入
for (int i = a.size() - 1; i >= 0; i -- ) A.push_back(a[i] - '0'); //将字符转化为数字,并倒序存储
for (int i = b.size() - 1; i >= 0; i -- ) B.push_back(b[i] - '0');
〇 高精度加法
1、核心模板
vector<int> add(vector<int> &A , vector<int> &B)
{vector<int> C; //定义变长数组C,用于储存答案int t = 0; //定义t用于记录进位数,初始化为0for(int i = 0;i < A.size() || i < B.size();i++) //中断条件:处理完A,B每一位上数字{if(i < A.size()) t += A[i]; if(i < B.size()) t += B[i]; //t进行上述步骤后,最终结果为 t+A[i]+B[i]C.push_back(t % 10); //t % 10得到相加后当前位上的数字并输进C数组t /= 10; //t / 10 得到进位数}if(t) C.push_back(1); //若最高位有进位数,则进1return C; //返回储存答案的数组C
}
〇 高精度减法
1、核心模板
vector<int> sub(vector<int> &A , vector<int> &B) //传入时需注意,A应为被减数,B为减数
{vector<int> C; //定义变长数组C用于储存答案for(int i = 0,t = 0;i < A.size();i++) //中断条件:处理完被减数的每一位,{ //并定义t用于记录借位数,初始化为0t = A[i] - t; //当前位数字减去借位数if(i < B.size()) t -= B[i]; //若B当前位上有数字,则减去,此时结果为A[i]-t-B[i]C.push_back((t + 10) % 10); //取得相减后当前位上数字,t+10是为了防止结果为负数if(t < 0) t = 1; //若t<0,说明向前借了一位,t更新为1else t = 0; //否则即未进行借位,t更新为0}while(C.size() > 1 && C.back() == 0) C.pop_back(); //去除前导零return C; //返回储存答案的变长数组C
}
〇 高精度乘法c
1、注
此处高精度乘法仅实现一高精度数乘一较小的数
2、核心模板
vector<int> mul(vector<int> &A , int B)
{vector<int> C; //定义变长数组C用于储存答案int t = 0; //定义t用于记录进位数for(int i = 0;i < A.size() || t;i++) //遍历每一位,分别乘以B{if(i < A.size()) t += A[i] * B; //计算结果C.push_back(t % 10); //取计算后当前位上数字,并输入C中 t /= 10; //取进位}return C; //返回储存答案的变长数组C
}
〇 高精度除法
1、注
除法与加、减、乘法不同,计算时从高位开始向低位处理,因此在储存时应从高位到低位进行储存
但为了应对多种运算混合存在的情况,为了与其他运算一致,故采用与加、减、乘法相同的储存方式,即从低位向高位储存
在除法处理时,进行倒序遍历即可
且计算后的结果C,也是由高位到低位储存,因此最后需将C逆序,使其为由低位向高位储存
2、核心模板
vector<int> div(vector<int> &A , int B , int &r ) //A是被除数,B是除数,r是余数
{vector<int> C; //定义变长数组C用于储存答案r = 0; //余数初始化为0for(int i = A.size() - 1;i >= 0;i--) //倒序处理A{r = r * 10 + A[i]; //将上次的余数*10在加上当前位的数字,便是该位需要除的被除数C.push_back(r / b); //所得即为商在这一位的数字r % b; //取得这一位的余数}reverse(C.begin() , C.end()); //将C数组逆序,使其由低位到高位储存while(C.size() > 1 && C.back() == 0) C.pop_back(); //去除前导零return C; //返回储存答案的变长数组C
}
⩕ 前缀和
〇 一维前缀和
1、概念
对于一数组a,其中元素为 `a[0] = 0 , a[1] , a[2] ...`
定义一新数组s,其中元素为 `s[0] = 0 , s[1] = a[1] + a[0] , s[2] = a[2] + a[1] + a[0] ...`
则将 数组s 称为 数组a 的前缀和数组
2、核心模板
for(int i = 1;i <= n;i++)s[i] = s[i - 1] + a[i];
3、应用
可用于快速计算数组a中某区间的和
要计算 `a[l]` 到 `a[r]` 的和,即计算 `s[r] - s[l - 1]`;
〇二维前缀和
1、概念
对于一数组a,其中元素为`a[0][0] = 0,a[0][1],a[0][2] ...`
定义一新数组s,其中元素为`s[0][0] = 0,s[0][1] = a[0][0] + a[0][1]...s[1][1] = a[0][0] + a[0][1] +a[1][0] + a[1][1] ...`
则将 数组s 称为 数组a 的前缀和数组
2、核心模板
for(int i = 1;i <= n;i++)for(int j = 1;j <= m,j++)s[i][j] = s[i - 1][j] + s[i][j -1] + a[i][j] + a[i - 1][j - 1];
3、应用
可用于快速求矩阵中以 ( x1 , y1 ) , ( x2 , y2 )为对角线的矩形区域的和
和即`s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]`
⩕ 差分
〇 一维差分
1、概念
对于一 数组a,其中元素为 `a[1] , a[2] , a[3] ...`
构造一新 数组b,其中元素满足,`b[1] = a[1],b[1] + b[2] = a[2],b[1] + b[2] + b[3] = a[3] ...`
即 数组a 是 数组b 的前缀和数组,将 数组b 称为 数组a 的差分
2、原理
将 数组a 初始全视为0,再执行一插入操作,即可达成差分的效果
3、核心模板
void insert(int l,int r,int c)
{b[l] += c;b[r + 1] -= c;
}
... ...
for(int i = 1;i <= n;i++) insert( i , i , a[i]);
4、应用
可快速完成将 [ l , r ] 区间的元素均加上 c 的操作,执行 insert 函数即可
对 数组b 做前缀和,即可得到 数组a
〇 二维差分
1、核心模板
void insert(int x1,int y1,int x2,int y2,int c)
{b[x1][y1] += c;b[x2 + 1][y1] -= c;b[x1][y2 + 1] -= c;b[x2 + 1][y2 + 1] += c;
}
... ...
for(int i = 1;i <=n ;i++)for(int j = 1;j <= n;j++)insert( i , j , i , j , a[i][j]);
2、注
其余内容与一维差分同理
⩕ 离散化
1、概念
对一 数组a ,其中元素范围较,但元素分布较为分散,
定义一元素连续的新数组,将 数组a 中元素映射到该新数组上,此过程即为离散化
2、核心模板
vector<int> alls;
sort(alls.begin() , alls.end());
alls.erase(unique(alls.begin() , alls.end()) , alls.end());
int find(int x)
{int l = 0,r = alls.size() - 1;while(l < r){int mid = l + r >> 1;while(l < r){if(alls[mid] >= x) r = mid;else l = mid + 1;}}return r + 1;
}
# ——————————————————————————————
⩕ 区间合并
1、概念
给定n个区间,将所有有交集的区间合并
2、原理
维护一新区间,对n个区间依左端点进行排序,再对n个区间进行遍历,有以下三种情况
1、与维护区间无交集,不处理
2、与维护区间由交集,合并
3、包含于维护区间,合并
3、核心模板
typedef pair<int,int> PII;
vector<PII> segs;
void merge(vector<PII> &segs)
{vector<PII> res;sort(segs.begin() , segs.end());int st = -2e9 , ed = -2e9;for(auto seg:segs)if(ed < seg.first){if(st != -2e9) res.push_back({st,ed});st = seg.first,ed = seg.second;}else ed = max(ed , seg.second);if(st != -2e9) res.push_back({st,ed})segs = res;
}
欢迎订阅专栏,数据结构实验,期末大作业,前端后端,算法都有哦,想我发哪个方面的资源或文章可以私信我,免费的哦