数据结构与算法2--数组常见操作
数组是最常见也是我们使用最多的数据结构了,它是一块连续的内存空间,以下标来描述空间的位置,C++中int arr[len]表示的的数组一旦配置后大小就无法改变,vector<int> v表示的数组可以动态增加。以下是笔者根据数组的特性和平时使用情况完成的一些基本功能,后续将根据使用情况再增加相关功能。
1、功能
00-打印数组
01-合并两个有序的数组
02-将数组排序为最小数字
03-查找连续的子序列
04-数组中逆序对
05-求素数对
06-求数组中是否有重复的数
07-求数组中和为S的数对
08-给定数组求新数组
2、代码
#include <iostream>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
/*
该文件夹包含array相关的各类常用功能和算法
*/
/*Menu
00-打印数组
01-合并两个有序的数组
02-将数组排序为最小数字
03-查找连续的子序列
04-数组中逆序对
05-求素数对
06-求数组中是否有重复的数
07-求数组中和为S的数对
08-给定数组求新数组
*/
void PrintArray(const int arr[],const int len);//00
void PrintArray(const vector<int> &arr);//00
void MergeSortedArray(int A[],int m,int B[],int n);//01
string PrintMinNumber(vector<int> nums);//02
vector<vector<int> > FindContinuousSequence(int sum);//03
int InversePairs1(vector<int> data);//04-1循环方法
int InversePairs2(vector<int> data);//04-2归并方法
int GetSuShuNum(int n);//05
bool IfDuplicate(vector<int> v,int &num);//06
vector<int> FindNumbersWithSum(vector<int> array,int sum);//07
//00-打印数组
void PrintArray(const int arr[],const int len)
{
cout<<'[';
for(int i=0;i<len;i++)
(i==(len-1))?(cout<<arr[i]<<']'<<endl):(cout<<arr[i]<<',');
}
void PrintArray(const vector<int> &arr)
{
cout<<'[';
for(int i=0;i<arr.size();i++)
(i==(arr.size()-1))?(cout<<arr[i]<<']'<<endl):(cout<<arr[i]<<',');
}
//01-合并两个有序的数组
void MergeSortedArray(int A[],int m,int B[],int n)
{
//合并B到A中,假设A空间足够大
int m1 = m-1;
int n1 = n-1;
int s = m1+n1+1;
while(m1>=0 && n1>=0)
{
if(A[m1]>=B[n1])
{
A[s--] = A[m1--];
}else
{
A[s--] = B[n1--];
}
}
if(n1>=0)
{
for(int i=0;i<=n1;i++)
A[i] = B[i];
}
}
void TestMergeSortedArray()
{
int A[9] = {1,2,3,4,5};
int B[4] = {2,4,6,8};
MergeSortedArray(A,5,B,4);
PrintArray(A,9);
}
//02-将数组排序为最小数字
bool CompareNumbers(int n1,int n2)
{
stringstream itoa;
itoa<<n1;
string str1 = itoa.str();
itoa<<n2;
string str2 = itoa.str();
if(str1<str2)
return true;
else
return false;//3<=34 true;23<=345 true;13<=124 false
}
string PrintMinNumber(vector<int> nums)
{
//例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
string str="";
if(nums.size()==0)
return str;
sort(nums.begin(),nums.end(),CompareNumbers);
for(int i=0;i<nums.size();i++)
{
stringstream itoa;
itoa<<nums[i];
str+= itoa.str();
}
return str;
}
void TestPrintMinNumber()
{
int arr[]={3,32,321};//含0的时候应该特殊处理,当前方法会把0放在末尾,实际最好把0放在第一个数字后面
vector<int> v(arr,arr + sizeof(arr)/sizeof(int));
string str = PrintMinNumber(v);
cout<<str<<endl;
}
//03-查找连续的子序列
vector<vector<int> > FindContinuousSequence(int sum) {
//输出所有和为Sum的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
vector<vector<int> > vret;
int n = sqrt(2*sum);//n((n+1)/2= sum
for(int i=2;i<=n;++i)
{
vector<int> tmp;
if(i&0x01)
{
if((sum%i)==0)
{
int mid = sum/i;
int first = mid - i/2;
for(int j=0;j<i;++j,++first)
tmp.push_back(first);
vret.push_back(tmp);
}
}else{
if((2*(sum/i) +1)*i/2 == sum) //(2*(sum/i) +1为中间两个值之和
{
int first = sum/i - i/2 +1;
for(int j=0;j<i;++j,++first)
tmp.push_back(first);
vret.push_back(tmp);
}
}
}
return vret;
}
void TestFindContinuousSequence()
{
vector<vector<int> >v;
v = FindContinuousSequence(21);
for(int i=0;i<v.size();i++)
PrintArray(v[i]);
}
//04-数组中逆序对
int InversePairs1(vector<int> data) {
long long ret = 0;
//* 时间复杂度O(n^2)
for(int i=0;i<data.size()-1;i++)
{
for(int j=i+1;j<data.size();j++)
if(data[i]>data[j])
ret++;
}
return (ret%1000000007);
}
int InversePairsCore(vector<int> &data, vector<int> ©,int start, int end) {
if(start==end){
copy[start] = data[end];
return 0;
}
int len = (end-start)/2;
int left = InversePairsCore(copy,data,start,start+len);
int right = InversePairsCore(copy,data,start+len+1,end);
//i初始化为前半段最后一个数字的下标
int i = start + len;
//j初始化为后半段最后一个数字的下标
int j = end;
int indexCopy = end;
int count = 0;
while(i>=start && j>=(start+len+1))
{
if(data[i]>data[j])
{
copy[indexCopy--] = data[i--];
count += j-start-len;
}else
{
copy[indexCopy--] = data[j--];
}
}
for(;i>=start;--i)
{
copy[indexCopy--] = data[i];
}
for(;j>=start+len+1;--j)
{
copy[indexCopy--] = data[j];
}
return left+right+count;
}
int InversePairs2(vector<int> data) {
int ret = 0;
if(data.size()==0)
return 0;
std::vector<int> vcopy;
for(int i=0;i<data.size();i++)
vcopy.push_back(data[i]);
ret = InversePairsCore(data,vcopy,0,data.size()-1);
vcopy.clear();
return (ret%1000000007);
}
void TestInversePairs()
{
//在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
//输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
int arr[]={1,2,3,4,5,6,7,0};
vector<int> v(arr,arr+sizeof(arr)/sizeof(int));
cout<<InversePairs2(v)<<endl;
}
//05-求素数对
bool IsSuShu(int n)
{
bool ret= true;
if(n==1)
return false;
for(int i=2;i<=sqrt(n);i++)
{
if(n%i==0)
return false;
}
return ret;
}
void SumSuShu(int left,vector<int> v,int &num)
{
if(left==0)
{
num++;
return;
}else if(left>0 && v.size()>0)
{
vector<int> v1 = v;
for(int i=0;i<v.size();i++)
{
int tmp = v1[0];
v1.erase(v1.begin()+0);
SumSuShu(left-tmp,v1,num);
}
}else
{
return ;
}
}
int GetSuShuNum(int n)
{
//给定一个正整数,编写程序计算有多少对质数的和等于输入的这个正整数,并输出结果。输入值小于1000。如,输入为10, 程序应该输出结果为2。(共有两对质数的和为10,分别为(5,5),(3,7))
int ret = 0;
vector<int> v;
for(int i=1;i<=n;i++)
{
if(IsSuShu(i))
{
v.push_back(i);
}
}
//使用递归查找有效数对
PrintArray(v);
int len = v.size();
for(int i=0;i<len;i++)
{
int tmp = v[0];
v.erase(v.begin()+0);
SumSuShu(n-tmp,v,ret);
}
return ret;
}
void TestGetSuShuNum()
{
int n = 10;
cout<<n<<":"<<GetSuShuNum(n)<<endl;
}
//06-求数组中是否有重复的数
bool IfDuplicate(vector<int>v,int &num)
{
//长度为n的数组v,其每个元素大小在0-n-1之间,num保存重复的数
if(v.size()==0)
return false;
for(int i=0;i<v.size();i++)
{
if(v[i]<0 || v[i]>(v.size()-1))
return false;
}
for (int i = 0; i < v.size(); ++i)
{
while(v[i]!=i)
{
if(v[i] == v[v[i]])
{
num = v[i];
return true;
}
int tmp = v[i];
v[i] = v[v[i]];
v[tmp] = tmp;
}
}
return false;
}
void TestIfDuplicate()
{
int num = 0;
int arr[] = {1,2,3,4,5,6,7,7,8,9,9,10};
std::vector<int> v(arr,arr+sizeof(arr)/sizeof(int));
(IfDuplicate(v,num))?(cout<<"True\t"<<num<<endl):cout<<"False\t"<<endl;
}
//07-求数组中和为S的数对
vector<int> FindNumbersWithSum(vector<int> array,int sum)
{
//输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,
//如果有多对数字的和等于S,输出两个数的乘积最小的。
vector<int> vret;
int min = 0;
int max = array.size()-1;
while(min<max)
{
if(array[min]+array[max]==sum)
{
vret.push_back(array[min]);
vret.push_back(array[max]);
return vret;
}
while(min<max && (array[min]+array[max]>sum)) --max;
while(min<max && (array[min]+array[max]<sum)) ++min;
}
return vret;
}
void TestFindNumbersWithSum()
{
int arr[] = {1,2,3,4,5,6,9,10,11,15,17,19,30};
vector<int> v(arr,arr+sizeof(arr)/sizeof(int));
std::vector<int> vret = FindNumbersWithSum(v,15);
PrintArray(vret);
}
//08--给定数组求新数组
vector<int> multiply(const vector<int>& A) {
//给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素
//B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
vector<int> v1,v2,vret;
int ret = 1;
int len = A.size();
for(int i=0;i<len;i++)
{
if(i>0){ret = ret*A[i-1];v1.push_back(ret);}
else v1.push_back(1);
}
ret = 1;
for(int j=len-1;j>=0;--j)
{
if(j<len-1){ret=ret*A[j+1];v2.push_back(ret);}
else v2.push_back(1);
}
for(int i=0;i<len;i++)
{
vret.push_back(v1[i]*v2[len-1 -i]);
}
return vret;
}
void TestMultiply()
{
int arr[] = {1,2,3,4,5};
PrintArray(arr,5);
vector<int> v(arr,arr+sizeof(arr)/sizeof(int));
vector<int> vret = multiply(v);
PrintArray(vret);
}
int main()
{
//01-合并两个有序的数组
//TestMergeSortedArray();
//02-将数组排序为最小数字
//TestPrintMinNumber();
//03-查找连续的子序列
//TestFindContinuousSequence();
//04-数组中逆序对
//TestInversePairs();
//05-求素数对
//TestGetSuShuNum();
//06-求数组中是否有重复的数
//TestIfDuplicate();
//07-求数组中和为S的数对
//TestFindNumbersWithSum();
//08-给定数组求新数组
TestMultiply();
return 0;
}
3、说明
当前已在mingw32(gcc 4.9.2)上测试通过。