/**
part4 递归 回溯 分治
递归函数基础:
函数体内部出现了再次调用当前函数的语句
每个递归函数中都必须有递归结束/终止条件,当条件满足时,递归终止。
如: 用递归算法实现 1+2+3
**/
#include<iostream>
#include<vector>
using namespace std;
void compute_sum(int i,int &sum,int n){
// 函数的参数sum为引用类型,则将形参传入时
// 在函数体中对于形参的修改将直接体现在对传入参数的修改上
if(i>n){
return;
}
sum+=i;
compute_sum(i+1,sum,n);
}
int main(){
int sum=0;
compute_sum(1,sum,3);
cout<<"1+2+3= "<<sum<<endl;
return 0;
}
/**
递归函数应用:
编写递归函数,实现功能:将链表中的数值按次序push到vector中
**/
#include<iostream>
#include<vector>
using namespace std;
struct ListNode{
int val;
ListNode *next;
ListNode(int x):val(x),next(NULL){}
};
void add_to_vector(ListNode *head,vector<int> &vec){
// & 表示传入的参数是引用类型,
if(head==NULL){
return;
}
vec.push_back(head->val);
add_to_vector(head->next,vec);
}
int main(){
ListNode a(1);
ListNode b(2);
ListNode c(3);
ListNode d(4);
ListNode e(5);
a.next=&b;
b.next=&c;
c.next=&d;
d.next=&e;
vector<int> result;
add_to_vector(&a,result);
for(int i=0;i<result.size();i++){
cout<<result[i]<<endl;
}
return 0;
}
/**
回溯法
利用递归的思想解决问题的一种算法
回溯法又称为试探法,但当探索到某一步时,发现原先选择
达不到目标,就退回一步重新选择,这种走不通再退回的技术
为回溯法
**/
学习算法的过程中,不能仅仅看视频学知识,还要多做相关的联系,以掌握算法。
#include<iostream>
#include<vector>
using namespace std;
/**
leetcode 78 子集
给定一组不含重复元素的整数数组 nums
返回该数组所有可能的子集(幂集)
说明:解集不能包含重复的子集
**/
class Solution {
public:
vector<vector<int> > choose_n(vector<int>& nums,int n,int start_index){
// 返回从nums数组中选择出n个元素的所有可能的组合形式
// 如 choose([1,2,3],1,0)=[[1],[2],[3]]
vector<vector<int> > output;
if(n==0 or n>nums.size()){
return output;
}
if(n==1){
for(int i=start_index;i<nums.size();i++){
vector<int> temp;
temp.push_back(nums[i]);
output.push_back(temp);
}
return output;
}
for(int i=start_index;i<nums.size();i++){
vector<vector<int> > saved=this->choose_n(nums,n-1,i+1);
for(int j=0;j<saved.size();j++){
vector<int> temp;
temp.push_back(nums[i]);
temp.insert(temp.end(),saved[j].begin(),saved[j].end());
output.push_back(temp);
//cout<<"inside recurrion"<<endl;
}
}
return output;
}
vector<vector<int> > subsets(vector<int>& nums) {
vector<vector<int> > result;
if(nums.size()==0){
return result;
}
if(nums.size()==1){
vector<int> temp;
result.push_back(temp);
result.push_back(nums);
return result;
}
vector<int> c_n_0;
result.push_back(c_n_0);
for(int i=1;i<nums.size();i++){
vector<vector<int> > output=this->choose_n(nums,i,0);
result.insert(result.end(),output.begin(),output.end());
}
result.push_back(nums);
return result;
}
};
int main(){
vector<int> input;
for(int i=1;i<=3;i++){
input.push_back(i);
}
Solution s;
vector<vector<int> > result;
result=s.subsets(input);
for(int i=0;i<result.size();i++){
for(int j=0;j<result[i].size();j++){
cout<<result[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
/**
leetcode 78. 子集
方法2:利用位运算输出vector的所有子集
对vector中的元素按照index进行编码
element value index code
vector[0] 1 0 001=1
vector[1] 2 1 010=2
vector[2] 3 2 100=4
对于所有包含3个元素的vector而言,共有2**3=8种子集
每个子集实际上都对应一个整数
**/
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
vector<vector<int> > subsets(vector<int>& nums){
vector<vector<int> > result;
if(nums.size()==0){
return result;
}
if(nums.size()==1){
vector<int> temp;
result.push_back(temp);
result.push_back(nums);
return result;
}
int total_length=1<<nums.size();
// cout<<total_length<<"here "<<endl;
// 表示最终输出的子集的长度
// vector<int> encoded;
// for(int i=0;i<nums.size();i++){
// encoded.push_back(2<<i);
// }
// 根据索引下标的位置对输入的元素进行编码
for(int i=0;i<total_length;i++){
vector<int> temp;
int temp_sum=i;
for(int j=nums.size()-1;j>=0;j--){
if(temp_sum<0){
break;
}
if(temp_sum>=1<<j){
temp.push_back(nums[j]);
temp_sum-=1<<j;
}
}
result.push_back(temp);
}
return result;
}
};
int main(){
vector<int> input;
for(int i=1;i<=3;i++){
input.push_back(i);
}
Solution s;
vector<vector<int> > result;
result=s.subsets(input);
for(int i=0;i<result.size();i++){
for(int j=0;j<result[i].size();j++){
cout<<result[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
/**
leetcode 90. 子集 II
给定一个可能包含重复元素的整数数组nums,
返回该数组所有可能的子集(幂集)
说明:解集不能包含重复的子集。
**/
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
vector<vector<int> > choose_n(vector<int>& nums,int total,int start_index){
vector<vector<int> > output;
if(total==0 or start_index>=nums.size()){
return output;
}
if(total==1){
int i=start_index;
while(i<nums.size()){
vector<int> temp;
temp.push_back(nums[i]);
output.push_back(temp);
i++;
while(i<nums.size() and nums[i]==nums[i-1]){
i++;
}
}
return output;
}
int k=start_index;
while(k<nums.size()){
vector<vector<int> > rec_output=this->choose_n(nums,total-1,k+1);
for(int i=0;i<rec_output.size();i++){
vector<int> temp;
temp.push_back(nums[k]);
temp.insert(temp.end(),rec_output[i].begin(),rec_output[i].end());
output.push_back(temp);
}
k++;
while(k<nums.size() and nums[k]==nums[k-1]){
k++;
}
}
return output;
}
vector<vector<int> > subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int> > result;
if(nums.size()==0){
return result;
}
if(nums.size()==1){
vector<int> temp;
result.push_back(temp);
result.push_back(nums);
return result;
}
// 在递归回溯的过程中进行去重
vector<int> temp;
result.push_back(temp);
for(int i=1;i<nums.size();i++){
vector<vector<int> > output;
output=this->choose_n(nums,i,0);
result.insert(result.end(),output.begin(),output.end());
}
result.push_back(nums);
return result;
}
};
int main(){
vector<int> input;
for(int i=1;i<=3;i++){
input.push_back(i);
}
input[input.size()-1]--;
Solution s;
vector<vector<int> > result;
result=s.subsetsWithDup(input);
for(int i=0;i<result.size();i++){
for(int j=0;j<result[i].size();j++){
cout<<result[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
/**
leetcode 40. 组合总和 II
给定一个数组 candidates 和一个目标数 target
找出 candidates 中所有可以使数字和为 target 的组合
candidates 中的每个数字在每个组合中只能使用一次
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
**/
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Solution {
public:
void find_sum(vector<vector<int> >& result,vector<int>& candidates,int target,int index){
// 从candidates的初始索引为index开始,找到所有和为target的组合
// 返回的组合序列的第一个元素必然是 candidates[index]
if(target<=0 or candidates[index]>target){
return;
}
if(candidates[index]==target){
vector<int> temp;
temp.push_back(candidates[index]);
result.push_back(temp);
}
target=target-candidates[index];
// 在递归函数内部进行去重
int i=index+1;
while(i<candidates.size()){
if(candidates[i]>target){
return;
}
else{
vector<vector<int> > result_rec;
this->find_sum(result_rec,candidates,target,i);
for(int j=0;j<result_rec.size();j++){
vector<int> temp;
temp.push_back(candidates[index]);
temp.insert(temp.end(),result_rec[j].begin(),result_rec[j].end());
result.push_back(temp);
}
i++;
while(i<candidates.size() and candidates[i]==candidates[i-1]){
i++;
}
}
}
}
vector<vector<int> > combinationSum2(vector<int>& candidates, int target) {
vector<vector<int> > result;
sort(candidates.begin(),candidates.end());
if(candidates[0]>target){
return result;
}
// 需要给子函数中的start_index参数赋值以进行去重
int index=0;
while(index<candidates.size()){
vector<vector<int> > output;
this->find_sum(output,candidates,target,index);
result.insert(result.end(),output.begin(),output.end());
index++;
while(index<candidates.size() and candidates[index]==candidates[index-1]){
index++;
}
}
return result;
}
};
int main(){
int a[7]={10,1,2,7,6,1,5};
vector<int> b;
for(int i=0;i<7;i++){
b.push_back(a[i]);
}
Solution s;
vector<vector<int> > result=s.combinationSum2(b,8);
for(int i=0;i<result.size();i++){
for(int j=0;j<result[i].size();j++){
cout<<result[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
如何检查自己是否理解了某个代码:再做一些考查这个算法的编程题,看看是否能做得出来。
/**
leetcode 22. 括号生成
给出 n 代表生成括号的对数
请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
**/
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
void concrete_generate(int n,string str,int used_left,int used_right,vector<string>& result){
// cout<<"each iteration: "<<str<<endl;
//
// cout<<"used_left: "<<used_left<<" used_right: "<<used_right<<endl;
if(used_left<used_right){
return;
}
// n:需要生成括号的对数,
// 当前的字符串str,
// used_left 当前的字符串中已经包含的左括号字符数
// used_right 当前的字符串中已经包含的右括号字符数
// result 输出的结果,最终输出的所有可能的字符串
if(str.length()>n*2 or used_left>n or used_right>n){
return;
}
if(str.length()==n*2 and used_left==n and used_right==n){
result.push_back(str);
// cout<<"-----------push_back: "<<str<<endl;
return;
}
if(used_left==used_right and used_left<n){
// string str1=str+"(";// 当左括号数量与右括号数量相等时,则只能添加左括号
// vector<string> result_rec;
this->concrete_generate(n,str+"(",used_left+1,used_right,result);
// cout<<"here: "<<result_rec.size()<<endl;
//
// for(int i=0;i<result_rec.size();i++){
// result.push_back(str1+result_rec[i]);
// }
if(used_left>0){
// 说明还可以添加右括号
// string str2=str+")";
//vector<string> result_rec2;
this->concrete_generate(n,str+")",used_left,used_right+1,result);
// for(int i=0;i<result_rec2.size();i++){
// result.push_back(str2+result_rec[i]);
// }
}
}
if(used_left>used_right){
// 添加右括号
// string str2=str+")";
// vector<string> result_rec3;
this->concrete_generate(n,str+")",used_left,used_right+1,result);
// for(int i=0;i<result_rec3.size();i++){
// result.push_back(str2+result_rec3[i]);
// }
if(used_left<n){
// 添加左括号
// string str4=str+"(";
//vector<string> result_rec4;
this->concrete_generate(n,str+"(",used_left+1,used_right,result);
// for(int i=0;i<result_rec.size();i++){
// result.push_back(str4+result_rec[i]);
// }
}
}
return;
}
vector<string> generateParenthesis(int n) {
vector<string> result;
if(n==0){
return result;
}
if(n==1){
result.push_back("()");
return result;
}
this->concrete_generate(n,"",0,0,result);
return result;
}
};
int main(){
Solution s;
vector<string> result;
result=s.generateParenthesis(3);
cout<<"total element: "<<result.size()<<endl;
for(int i=0;i<result.size();i++){
cout<<result[i]<<endl;
}
return 0;
}
#include<iostream>
#include<vector>
#include<string>
#include<stdlib.h>
using namespace std;
/**
leetcode 51. N皇后
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上
并且使皇后彼此之间不能相互攻击。
使用递归/回溯算法
这种算法的时间复杂度太高了,并没有对问题分析透彻就开始写代码了
**/
class Solution
{
public:
vector<vector<string> > concrete_start(int n,int acc,int leave,int start_row,int start_col,vector<vector<int> > matrix_flag,vector<string> choose)
{
// cout<<"进入本次迭代...."<<start_row<<", "<<start_col<<endl;
/**
acc 表示累计到现在共有多少个queen被放置到了二维矩阵中
start_row和start_col表示的就是当前步骤所需要选择放置queen的位置
放置完成后,对matrix_flag的相应位置上做标记
leave 表示当前的matrix_flag中还有多少个位置点是可以被放置的,即在安全范围内的
**/
if(leave<n-acc)
{
// 如果当前棋盘格上的没有攻击性的点数小于所需要的剩余点数,则说明无法构成
vector<vector<string> > empty1;
return empty1;
}
matrix_flag[start_row][start_col]=1;
choose[start_row].replace(start_col,1,"Q");
// 再将以当前位置辐射出去的所有位置范围内的位置点都变成1
acc++;
leave--;
vector<vector<string> > result;
if(acc==n)
{
// 如果choose中为'Q'的字符总数为n,则表示找到了以start_row和start_col为起始点的N皇后棋盘
// 则choose有意义
result.push_back(choose);
return result;
}
// 将start_row所在的行变成1
for(int i=start_col-1;i>=0;i--)
{
if(matrix_flag[start_row][i]==0){
matrix_flag[start_row][i]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
}
for(int i=start_col+1;i<n;i++){
if(matrix_flag[start_row][i]==0){
matrix_flag[start_row][i]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
}
// 将start_col所在的列变成1
for(int j=start_row-1; j>=0;j--){
if(matrix_flag[j][start_col]==0){
matrix_flag[j][start_col]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
}
for(int j=start_row+1; j<n;j++){
if(matrix_flag[j][start_col]==0){
matrix_flag[j][start_col]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
}
// 将主对角线45度所在的元素变成1
int up_i=start_row-1;
int up_j=start_col-1;
while(up_i>=0 and up_j>=0){
if(matrix_flag[up_i][up_j]==0){
matrix_flag[up_i][up_j]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
up_i--;
up_j--;
}
up_i=start_row+1;
up_j=start_col+1;
while(up_i<n and up_j<n){
if(matrix_flag[up_i][up_j]==0){
matrix_flag[up_i][up_j]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
up_i++;
up_j++;
}
// 将次对角线上的所有元素变成1
up_i=start_row-1;
up_j=start_col+1;
while(up_i>=0 and up_j<n){
if(matrix_flag[up_i][up_j]==0){
matrix_flag[up_i][up_j]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
up_i--;
up_j++;
}
up_i=start_row+1;
up_j=start_col-1;
while(up_i<n and up_j>=0){
if(matrix_flag[up_i][up_j]==0){
matrix_flag[up_i][up_j]=1;
leave--;
// if(leave<n-acc){
// return false;
// }
}
up_i++;
up_j--;
}
// cout<<"matrix_flag: "<<matrix_flag.size()<<", "<<matrix_flag[0].size()<<endl;
// cout<<"n= "<<n<<endl;
// 选作下一个放置皇后的坐标点必须是在当前的坐标点之后
// 即将当前坐标点之前行所有坐标点都变成1
// 并且将当前行此列之前的所有坐标点都变成1
for(int i=0;i<=start_row;i++){
for(int j=0;j<n;j++){
if(matrix_flag[i][j]==0){
matrix_flag[i][j]=1;
leave--;
}
}
}
for(int i=0;i<start_col;i++){
if(matrix_flag[start_row][i]==0){
matrix_flag[start_row][i]=1;
leave--;
}
}
if(leave<n-acc){
vector<vector<string> > empty1;
return empty1;
}
vector<vector<string> > result_rec;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(matrix_flag[i][j]==0){
// cout<<"i:"<<i<<" j:"<<j<<endl;
result_rec=this->concrete_start(n,acc,leave,i,j,matrix_flag,choose);
// cout<<"完成本次迭代...."<<start_row<<", "<<start_col<<" flag= "<<flag<<endl;
if(result_rec.size()>0){
result.insert(result.end(),result_rec.begin(),result_rec.end());
}
}
}
}
return result;
}
vector<vector<string> > solveNQueens(int n)
{
vector<vector<string> > result;
vector<vector<int> > had_chosen;// 表示当前的起始点已经被选择
for(int i=0;i<n;i++){
vector<int> temp2;
for(int j=0;j<n;j++){
temp2.push_back(0);
}
had_chosen.push_back(temp2);
}
// vector<string> init_choose;
// vector<vector<int> > init_matrix_flag;
// for(int k=0;k<n;k++){
// string temp="";
// vector<int> temp_line;
// for(int p=0;p<n;p++){
// temp+=".";
// temp_line.push_back(0);
// }
// init_choose.push_back(temp);
// init_matrix_flag.push_back(temp_line);
// }
vector<vector<string> > temp_result;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
// if(had_chosen[i][j]==0){
// cout<<"start position: "<<i<<", "<<j<<endl;
vector<string> init_choose;
vector<vector<int> > init_matrix_flag;
for(int k=0;k<n;k++){
string temp="";
vector<int> temp_line;
for(int p=0;p<n;p++){
temp+=".";
temp_line.push_back(0);
}
init_choose.push_back(temp);
init_matrix_flag.push_back(temp_line);
}
//cout<<"选择了一个新的初始点: "<<i<<", "<<j<<endl;
temp_result=this->concrete_start(n,0,n*n,i,j,init_matrix_flag,init_choose);
if(temp_result.size()>0){
result.insert(result.end(),temp_result.begin(),temp_result.end());
}
// }
cout<<"选择了一个新的初始点: "<<i<<", "<<j<<endl;
cout<<"以当前节点作为第一个点的可能情况"<<temp_result.size()<<endl;
}
}
return result;
}
};
int main(){
// string a="aaaaa";
// a.replace(0,1,"m");
// // C++中的字符串string替换某个索引位置的字符需要使用replace函数
// cout<<a<<endl;
Solution s;
vector<vector<string> > result;
int n=9;
result=s.solveNQueens(n);
for(int i=0;i<result.size();i++){
for(int j=0;j<result[i].size();j++){
cout<<result[i][j]<<","<<endl;
}
cout<<endl;
}
cout<<result.size()<<endl;
return 0;
}
#include<iostream>
#include<vector>
using namespace std;
/**
对问题进行具体分析后可以发现,
n*n矩阵的每一行都只能放置一个Queue,
每一列也只能放置一个Queue
必须要明确的几点是:
无论n为何值,N皇后问题至少包含1个解
这意味着只需要迭代(循环考虑)第0行Queue所要放置的列即可
故最外层循环需要循环N次
循环考虑第0行所需要放置的位置,再观察后面的行可能放置的位置
**/
class Solution {
public:
vector<vector<string> > pos_each_line(int line_num,int col,vector<int> choose_row,vector<int> choose_col,vector<bool> col_used,vector<string> choose){
// line_num 表示当前所考虑的行数,从第0行开始
// col 表示所选择需要放置的列数,
// matrix_flag 选择在第line_num行、第col列放置queen之前,matrix_flag中为1的位置表示不能放置queen的非法位置
// choose 表示在将queen放置到第line_num行、第col列之前,所选择的字符串
//choose_row 表示在第line_num行之前所选择的所有行数
//choose_col 表示在第line_num行之前所选择的所有列数
int n=choose.size();
// matrix_flag[line_num][col]=1;
choose[line_num].replace(col,1,"Q");
if(line_num==n-1){
vector<vector<string> > result_rec;
result_rec.push_back(choose);
return result_rec;
}
if(line_num==n){
vector<vector<string> > result_rec;
//result_rec.push_back(choose);
return result_rec;
}
choose_row.push_back(line_num);
choose_col.push_back(col);
col_used[col]=true;
line_num++;
// 下一行不能选择的列,为true则表示已经被前面的行选择过了
vector<bool> invalid_col=col_used;
for(int k=0;k<choose_col.size();k++){
// 根据之前选择过的点的对角线关系,确定在当前的行中不能选择哪些列
int pos_45=line_num+choose_col[k]-choose_row[k];
if(pos_45>=0 and pos_45<n){
invalid_col[pos_45]=true;
}
int neg_45=choose_col[k]+choose_row[k]-line_num;
if(neg_45>=0 and neg_45<n){
invalid_col[neg_45]=true;
}
}
// 给出下一行所能选择的列
vector<vector<string> > result;
int invalid_num=0;
vector<int> valid_col_set;
for(int i=0;i<n;i++){
if(invalid_col[i]!=true){
valid_col_set.push_back(i);
}
}
if(valid_col_set.size()==0){
vector<vector<string> > result_rec;
//result_rec.push_back(choose);
return result_rec;
}
for(int i=0;i<valid_col_set.size();i++){
// 说明在下一行可以选择当前列数
vector<vector<string> > result_rec;
result_rec=this->pos_each_line(line_num,valid_col_set[i],choose_row,choose_col,col_used,choose);
if(result_rec.size()>0){
result.insert(result.end(),result_rec.begin(),result_rec.end());
}
}
return result;
}
vector<vector<string> > solveNQueens(int n) {
vector<vector<string> > result;
vector<string> init_choose;
for(int i=0;i<n;i++){
string temp="";
for(int j=0;j<n;j++){
temp+=".";
}
init_choose.push_back(temp);
}
vector<bool> col_used_init;
for(int i=0;i<n;i++){
col_used_init.push_back(false);
}
for(int i=0;i<n;i++){
// i表示第0行所需要放置Queen的列数/位置
vector<vector<string> > temp_result;
vector<int> choose_row;
vector<int> choose_col;
vector<bool> col_used=col_used_init;
// C++ 中的赋值运算符是deep copy,将会在内存空间中额外开辟存储空间存放col_used
// 修改col_used的数值并不会影响col_used_init
temp_result=this->pos_each_line(0,i,choose_row,choose_col,col_used,init_choose);
if(temp_result.size()>0){
result.insert(result.end(),temp_result.begin(),temp_result.end());
}
}
return result;
}
};
int main(){
// string a="aaaaa";
// a.replace(0,1,"m");
// // C++中的字符串string替换某个索引位置的字符需要使用replace函数
// cout<<a<<endl;
Solution s;
vector<vector<string> > result;
int n=9;
result=s.solveNQueens(n);
for(int i=0;i<result.size();i++){
for(int j=0;j<result[i].size();j++){
cout<<result[i][j]<<","<<endl;
}
cout<<endl;
}
cout<<result.size()<<endl;
return 0;
}
/**
归并两个已经排序的数组
已知两个已经排序的数组,将这两个数组合并为一个排序数组
分治算法:
将一个规模为N的问题分解为K个规模较小的子问题
这些子问题相互独立且与原问题性质相同
求出子问题的解后进行合并,就可得到原问题的解
一般步骤:
将原问题分解成若干规模较小的同类问题
当子问题被划分得足够小时,用较简单的方法求解(递归函数的递归基)
合并:将子问题的解逐层和并构成原问题的解
在代码中体现为:
递归基的解(当问题的规模被划分得足够小时,用简单的方法即可得到问题的解)
对大规模的原问题进行划分,划分成K个规模较小的子问题
对K个子问题分别进行求解
对K个子问题的解进行合并
**/
#include<vector>
#include<iostream>
#include<assert.h>
#include<algorithm>
using namespace std;
void merge_sort_two_vec(vector<int> &sub_vec1,vector<int> &sub_vec2,vector<int> &vec){
int i=0;
int j=0;
while(i<sub_vec1.size() and j<sub_vec2.size()){
if(sub_vec1[i]<=sub_vec2[j]){
vec.push_back(sub_vec1[i]);
i++;
}
else{
vec.push_back(sub_vec2[j]);
j++;
}
}
for(;i<sub_vec1.size();i++){
vec.push_back(sub_vec1[i]);
}
for(;j<sub_vec2.size();j++){
vec.push_back(sub_vec2[j]);
}
}
void merge_sort(vector<int> &vec){
// 对输入的vector进行归并排序
// 归并排序的时间复杂度为O(NlogN)
if(vec.size()<=1){
return;// 当子问题的规模足够小时,直接求解
}
int mid=vec.size()/2;
// 对原问题进行分解,即对原数组拆分为两个规模相同的数组
// 再对它们分别进行排序
vector<int> sub_vec1;
vector<int> sub_vec2;
for(int i=0;i<mid;i++){
sub_vec1.push_back(vec[i]);
}
for(int j=mid;j<vec.size();j++){
sub_vec2.push_back(vec[j]);
}
merge_sort(sub_vec1);
merge_sort(sub_vec2);
vec.clear();// 将vec向量进行清空
merge_sort_two_vec(sub_vec1,sub_vec2,vec);// 将子问题的解进行合并
}
int main(){
// vector<int> sub_vec1;
// vector<int> sub_vec2;
//
// sub_vec1.push_back(2);
// sub_vec1.push_back(5);
// sub_vec1.push_back(8);
// sub_vec1.push_back(20);
//
// sub_vec2.push_back(1);
// sub_vec2.push_back(3);
// sub_vec2.push_back(5);
// sub_vec2.push_back(7);
// sub_vec2.push_back(30);
// sub_vec2.push_back(50);
//
// vector<int> vec;
//
// merge_sort_two_vec(sub_vec1,sub_vec2,vec);
// vector<int> vec;
// vec.push_back(5);
// vec.push_back(1);
// vec.push_back(4);
// vec.push_back(2);
// vec.push_back(3);
// int test1[]={-5,-7,9,8,1,4,-3,10,2,0};
// for(int i=0;i<10;i++){
// vec.push_back(test1[i]);
// }
vector<int> vec1;
vector<int> vec2;
srand(0);
// srand() 函数功能:初始化随机数发生器
// srand(int ) 传入的int类型整数用来设置rand()产生随机数时的随机种子
// rand() 函数不需要任何参数,它会返回一个从0到最大随机数的任意整数,
// 最大随机数的大小通常是固定的一个大整数
// 如果需要产生的随机数在0-100之间,则只需要rand()%101 即可
for(int i=0;i<10000;i++){
int num=(rand()*rand())/100003;
vec1.push_back(num);
vec2.push_back(num);
}
merge_sort(vec1);
sort(vec2.begin(),vec2.end());
assert(vec1.size()==vec2.size());
for(int i=0;i<vec1.size();i++){
assert(vec1[i]==vec2[i]);
}
return 0;
}