数据结构与算法2--数组常见操作

数据结构与算法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> &copy,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)上测试通过。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

昕光xg

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

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

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

打赏作者

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

抵扣说明:

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

余额充值