1. 需求确定
利用c/c++实现计算n的n次方(其中n为int型数据),并且最终输出结果不受编译器int或是long int等类型的存储位数限制的影响。n通过用户自行输入。
2. 技术难点
- 如何当结果的位数过大时依然完成对于数据的准确计算。(当所需存储的数值过大时将造成数值的越界)
- 降低算法的时间复杂度。
3. 实现思路
采用分治的思想利用n的2次方乘n的2次方得到n的4次方,再利用n的4次方计算n的8次方以此类推。这种方法的一般情况是当n等于2、4、8、16…也就是恰为2的几次方时为最理想情况,其他如n等于6时此方法只可计算到6的4次方,对于剩下的6的2次方需利用递归再次计算出6的2次方值为多少,最后再将这两个结果相乘得到最终结果。
相乘的实现则是通过将数据按位分离依次存入栈中,然后利用常规的竖式计算来计算任意位数的整数相乘。竖式计算所具有的特点如下图:
其中a表示存储a数据的栈的数据域,类似一维数组,z表示结果。由图中可看出结果的第0位为乘数第0位和被乘数第0位相乘所得结果与10取余,并将乘积除以10得到10位数字作为下一位的进位值,类推并归纳可得出:
z[n] = (a[x1]*b[y1]+a[x2]*b[y2]+···+上一位进位值)%10
其中x1+y1 = n,x2+y2 = n···
接下来的问题便是算法的c/c++实现。
4. c/c++实现
main.cpp:
#include<iostream>
#include"stack.h"
#include <windows.h>
using namespace std;
linkStack getMulResult(Stack p1, Stack p2, linkStack lsq);
Stack getFinalResult(int number, Stack sq);
Stack getCoupledResult(int number, Stack sq, bool IsOne);
int main() {
int number;
cin >> number;
double run_time;
Stack sq;
if (!creatStack(&sq)) {
cout << "栈空间创建失败" << endl;
exit(0);
}
int Num = number;
//将数据压入栈
while (number!=0) {
int _number = number % 10;
if (!pushStack(&sq, _number)) {
cout << "压栈失败!" << endl;
exit(0);
}
number = number / 10;
}
Stack ResultS = getFinalResult(Num, sq);
for (int i = ResultS.top; i >= 0; i--) {
//cout << result->s[i];
printf("%d", ResultS.s[i]);
}
destroyStack(&ResultS);
getchar();
getchar();
}
Stack getFinalResult(int number, Stack sq) {
if (number < 2) {
return sq;
}
int ComNum = 2;
while (ComNum <= number) {
ComNum *= 2;
}
ComNum /= 2;
Stack CouSq = getCoupledResult(ComNum, sq,true);
int AloneNumber = number - ComNum;
Stack AloneSq;
if (AloneNumber > 0) {
//处理剩余元素
AloneSq = getFinalResult(AloneNumber, sq);
//destroyStack(&sq);
Stack s;
linkStack result = &s;
creatStack(result);
getMulResult(CouSq, AloneSq, result);
destroyStack(&CouSq);
destroyStack(&AloneSq);
return *result;
}
else{
//内部无剩余
//destroyStack(&sq);
return CouSq;
}
}
Stack getCoupledResult(int number, Stack sq,bool IsOne) {
if (number <= 1) {
return sq;
}
Stack s;
linkStack result = &s;
creatStack(result);
Stack ResultSq = *getMulResult(sq, sq, result);
if (!IsOne) {
destroyStack(&sq);
}
return getCoupledResult(number / 2, ResultSq,false);
}
linkStack getMulResult(Stack p1, Stack p2, linkStack lsq) {
if (p2.top > p1.top) {
Stack t = p1;
p1 = p2;
p2 = t;
}
creatStack(lsq);
int ComIndex = 0;
if (p1.top <= -1 || p2.top <= -1) {
cout << "两数相乘传入数据不正确,已返回空栈!" << endl;
return lsq;
}
int MaxIndex = p1.top > p2.top? p1.top: p2.top; //两数中最长位数
int MinIndex = p2.top < p1.top?p2.top:p1.top;
int SumIndex = p1.top + p2.top; //结果位数总和
int NextAdd = 0;
for (int i = 0; i <= SumIndex; i++) {
//t和z为移动标志,用于记录那位相乘
int t = i;
if (i > MaxIndex) {
t = MaxIndex;
}
int z = 0;
int AddResult = NextAdd; //保留最后当前位的相加结果
while(t>=0&&z<= MinIndex) {
if (t + z == i) {
int ProductResult = p1.s[t] * p2.s[z];
AddResult += ProductResult;
//cout << "计算:" << i << " " << t << "," << z << " " << ProductResult << endl;
z++;
t--;
}
else {
z++;
}
}
NextAdd = AddResult / 10;
if (!pushStack(lsq, AddResult % 10)) {
cout << "两数计算过程入栈失败!" << endl;
exit(0);
}
}
if (NextAdd != 0) {
if (!pushStack(lsq, NextAdd)) {
cout << "两数计算过程入栈失败!" << endl;
exit(0);
}
}
return lsq;
}
Stack.h:
#include<stdio.h>
#include<stdlib.h>
#define OK 1 //操作成功
#define ERRO 0 //操作失败
#define MAX_LENGTH 100 //初次创建栈的最长长度
#define ADD_LENGTH 40 //每次扩展栈的长度
typedef int State; //利用BOOL表示操作是否成功
typedef int EmType;
typedef struct {
EmType* s; //数据
int top; //当前栈顶位置
int maxSize; //最大长度
}Stack, *linkStack;
//函数声明
State isFullStack(Stack s); //判断栈满
State creatStack(linkStack s_link); //创建空栈
State increaseStack(linkStack s_link); //为栈重新分配空间
State pushStack(linkStack s_link, EmType ch); //压栈
State isEmptyStack(linkStack s_link); //判断栈空
EmType popStack(linkStack s_link); //弹栈
void destroyStack(linkStack s); //销毁栈
Stack.cpp:
#include"stack.h"
//栈函数实现
/*************************************************
Function: popStack
Description: 弹栈
Input:s_link 栈指针
Return: 返回是否为空
*************************************************/
EmType popStack(linkStack s_link) {
return s_link->s[s_link->top--];
}
/*************************************************
Function: isEmptyStack
Description: 判断栈空
Input:s_link 栈指针
Return: 返回是否为空
*************************************************/
State isEmptyStack(linkStack s_link) {
if (s_link->top == -1)
return OK;
else
return ERRO;
}
/*************************************************
Function: creatStack
Description: 为栈分配空间
Input:s_link 栈指针
Return: 返回是否执行成功
*************************************************/
State creatStack(linkStack s_link) {
//为栈数据域分配连续空间
s_link->s = (EmType*)malloc(MAX_LENGTH * sizeof(EmType));
//判断是否分配成功
if (s_link->s == NULL) return ERRO;
//部分内容初始化
s_link->maxSize = MAX_LENGTH;
s_link->top = -1;
return OK;
}
/*************************************************
Function: pushStack
Description: 压栈
Input:s_link 栈指针
Return: 返回是否执行成功
*************************************************/
State pushStack(linkStack s_link, EmType ch) {
if (isFullStack(*s_link)) { //判断是否栈满,栈满则重新分配空间,否则直接压栈
//栈满
if (!increaseStack(s_link)) //重新分配栈空间,并判断是否分配成功
return ERRO;
}
s_link->s[++s_link->top] = ch;
return OK;
}
/*************************************************
Function: increaseStack
Description: 为栈重新分配空间
Input:s_link 栈指针
Return: 返回是否执行成功
*************************************************/
State increaseStack(linkStack s_link) {
//重新分配栈空间
s_link->s = (EmType*)realloc(s_link->s, sizeof(EmType)*(s_link->maxSize + ADD_LENGTH));
if (s_link->s == NULL) //判断是否分配空间成功
return ERRO;
s_link->maxSize += ADD_LENGTH;
return OK;
}
/*************************************************
Function: isFullStack
Description: 判断栈满
Input:s_link 栈指针
Return: 返回是否执行成功
*************************************************/
State isFullStack(Stack s) {
//如果当前top+1与栈最大空间相等则判断为栈满
if (s.maxSize == s.top + 1)
return OK;
else
return ERRO;
}
/*************************************************
Function: destroyStack
Description: 销毁栈
Input:s_link 栈指针
Return: 返回是否执行成功
*************************************************/
void destroyStack(linkStack s) {
free(s->s);
s->top = -1;
}
实现环境:
windows + vs2015
如果不习惯多文件共同编译,可以将所有代码都复制到main.cpp里面,应该没什么问题,需要请自行解决。
5. 注意事项
代码中使用了内存分配函数malloc,注意一定要在申请内存之后使用free函数释放掉,否则将造成严重的内存泄露。
6. 当前存在的问题和优化方向
问题:通过vs的debug功能,发现当前代码可能仍存在内存泄露问题,但是不是特别严重。
优化方向:
- 解决内存泄露问题
- 优化算法,降低时间复杂度,优化方向为从对于遗留数据也就是2次方之外的数据比如6的6次方中一次成对计算后的剩余的2次方的计算过程进行优化。