一、单项选择题(下列每题给出的4个选项中,只有一个最符合试题要求)
4. 已知一个栈的进栈序列为1,2,3,…,n,其输出序列是p
1,p
2,p
3,…,p
n。若p
1=3,则p
2的值______。
A B C D
D
[解析] 元素3第一个出栈时,元素1,2一定在栈内,下一个出栈的元素是2,不可能是1。当然还可以是元素2暂时不出栈,元素4,5,…进栈。
5. 已知一个栈的进栈序列为p
1,p
2,p
3,…,p
n,其输出序列是1,2,3,…,n。若p
3=1,则p
1的值______。
- A.一定是2
- B.可能是2
- C.不可能是2
- D.一定是3
A B C D
C
[解析] p3=1,输入序列为p1,p2,1,p4,…,因为p3=1,所以p3出栈前,p1,p2必在栈中。若p1出栈,则p2必先于p1出栈,因此p1不可能为2。
21. 已知一个栈的进栈序列为1,2,3,…,n,其输出序列是p
1,p
2,p
3,…,p
n。若p
1=n,则p
i的值是______。
A B C D
C
[解析] 一个出栈元素是n,则1,2,3,…,n-1都在栈内,可知后续出栈的元素依次为n-1,n-2,…,则第i个出栈元素应为n-i+1。
22. 已知一个栈的进栈序列为p
1,p
2,p
3,…,p
n,其输出序列是1,2,3,…,n。若p
3=3,则p
1的值是______。
- A.一定是2
- B.可能是2
- C.不可能是1
- D.一定是1
A B C D
B
[解析] 当p3=3时,输入序列为p1,p2,3,p4,…因为输出的第三个元素是3,所以有多种可能:当p1=1,p2=2时,允许的进栈或出栈顺序是p1进栈,p1出栈,p2进栈,p2出栈;当p1=2,p2=1时,允许的进栈或出栈顺序是p1进栈,p2进栈,p2出栈,p1出栈;当p1,p2,3进栈不出,p4=2,p5=1时,允许的进栈或出栈顺序可以是p4进栈,p5进栈,p5出栈,p4出栈。因此可以断定p1=1或p1=2是可能的,但不是一定的。
23. 已知一个栈的进栈序列为p
1,p
2,p
3,…,p
n,其输出序列是1,2,3,…,n。若p
n=1,则p
i的值是______。
A B C D
A
[解析] 当pn=1时,输入序列为p1,p2,p3,p4,…,pn-1,1,因为输出序列为1,2,3,…,n,所以第一次输出l时p1,p2,p3,p4,…,pn-1都应在栈内,这样可得pn-1=2,pn-2=3,…,pn-i=i+1,…,pi=n-i+1。
33. 设求解某问题的递归算法如下:
void F(int n)
{
if(n==1) Move(1);
else
{
F(n-1);
Move(n);
F(n-1);
}
}
在求解该算法的计算时间时,仅考虑算法Move所做的计算,且Move为常数级算法。算法F的计算时间T(n)的递推关系式为______。
- A.T(n)=T(n-1)+1
- B.T(n)=2T(n-1)
- C.T(n)=2T(n-1)+1
- D.T(n)=2T(n+1)+1
A B C D
C
[解析] 根据题目中程序代码的递归框架可知,该程序把一个规模为n的问题转化为两个规模为n-1的同样问题外加一个常量复杂度的操作来求解,因此其递推关系为T(n)=2T(n-1)+O(1),可近似为T(n)=2T(n-1)+1。
二、综合应用题1. 是否可以用两个栈模拟一个队列?反之,是否可以用两个队列模拟一个栈?
两个栈可以模拟一个队列,但反之不可。
原因如下:
栈是一种先进后出的线性结构,可以使用一个栈把一个输入序列逆转,同样可以使用另一个栈把逆转后的序列再逆转回来,因此用两个具有先进后出特性的栈可以模拟一个先进先出的队列。反之,两个先进先出的队列无法模拟一个栈。
2. 改写顺序栈的结构和进栈函数Push(x),要求当栈满时执行一个stackFull()操作进行溢出处理。其功能是:动态创建一个比原来的栈数组大一倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组的前maxSize个位置。
原顺序栈的程序代码如下:
typedef struct
{
int data[maxSize]; //存放栈中元素,maxSize是已定义的常量
int top; //栈顶指针
}SqStack; //顺序栈类型定义
原进栈函数程序代码如下:
int Push(SqStack &st,int x}
{
if(st.top==maxSize-1) //栈满不能进栈
return 0;
++(st.top); //先移动指针,再进栈
st.data[st.top]=x;
return 1;
}
原顺序栈的结构体中是用静态数组来存放数据,现在题目需要动态创建数组,因此需要把静态数组改掉,代码如下:
typedef struct
{
int *data; //指向动态数组的指针
int top; //栈顶指针
int maxSize; //因data数组是动态变化的,所以将maxSize改为变量
}SqStack;
修改后的Push()函数代码如下:
int Push(SqStack &st,int x)
{
if(st.top==st.maxSize-1) //栈满执行stackFull()
{
if(stackFull(st)==0) //栈满,且stackFull()函数失败,返回0
return 0; //否则只执行stackFull()
}
++(st.top); //先移动指针,再进栈
st.data[st.top]=x;
return 1;
}
stackFull()函数代码如下:
int StackFull(SqStack& st)
{
int *temp=(int*)malloc(2* st.maxSize * sizeof(int));
//申请一个动态数组空间长度为2倍的maxSize,由temp指向其首地址
if(temp==NULL)
return 0; //空间申请失败,返回0
for(int i=0;i<=st.top;++i)
temp[i]=st.data[i]; //复制原栈中元素到新空间的前一半地址
free(st.data); //释放原栈元素空间
st.data=temp; //用data指针指向新空问首地址
return 1; //成功,返回1
}
3. 将编号为0和1的两个栈存放于一个一维数组空间V[m]中,栈底分别处于数组的两端。当第0号栈的栈顶指针top[0]等于-1时,该栈为空;当第1号栈的栈顶指针top[1]等于m时,该栈为空。两个栈均从两端向中间增长,如图所示。当向第0号栈插入一个新元素时,使top[0]增1得到新的栈顶位置;当向第1号栈插入一个新元素时,使top[1]减1得到新的栈顶位置。当top[0]+1==top[1]时或top[0]==top[1]-1时,栈空间满,此时不能再向任意一个栈加入新的元素。试定义这种双栈结构,并实现初始化栈、判断栈空、判断栈满、元素入栈、元素出栈、取栈顶元素、清空栈运算算法。

(1)结构定义。
typedef struct //双栈的结构定义
{
int top[2],bot[2]; //双栈的栈顶指针和栈底指针
int *elem; //栈数组
int m; //栈数组最大可容纳元素个数
}DblStack;
(2)初始化栈。
void initStack(DblStack& S,int sz)
{//初始化函数:建立一个最大尺寸为sz的空栈,若分配不成功则进行错误处理
S.elem=(int*)malloc(sizeof(int)*sz); //创建栈的数组空间
if(S.elem==NULL){cout<<"memory assign fail"<<endl;exit(1);}
S.m=sz;
S.top[0]=S.bot[0]=-1;
S.top[1]=S.bot[1]=sz;
};
(3)判断栈空。
bool isEmpty(DblStack& S,int i)//判断栈i是否空
{
return S.top[i]==S.bot[i];
}
(4)判断栈满。
bool isFull(DblStack& S) //判断栈是否满
{
return S.top[0]+1==S.top[1];
}
(5)元素入栈。
bool Push(DblStack& S,int x,int i)
{//进栈,如果isFull(S),则报错;否则把x插入到栈i的栈顶
if(isFull(S))
return false; //栈满则返回false
if(i==0)
S.elem[++S.top[0]]=x; //栈0:栈顶指针先加,再进栈
else
S.elem[--S.top[1]]=x; //栈1:栈顶指针先减,再进栈
return true;
}
(6)元素出栈。
bool Pop(nblStack& S,int& x,int i)
{//如果栈空,则不执行退栈,返回false;否则退掉栈i栈顶元素到x,返回true
if(isEmpty(S,i)) //判断栈i是否空,若栈空则返回false
return false;
if(i==0)
x=S.elem[S.top[0]--; //栈0:先出栈,栈顶指针再减
else
x=S.elem[S.top[1]++]; //栈1:先出栈,栈顶指针再加
return true;
}
(7)取栈顶元素。
bool getTop(DblStack& S,int& x,int i)
(//若栈不空,则函数通过x返回该栈栈顶元素的内容
if(isEmpty(S,i))
return false; //判断栈i是否空,若栈空则返回false
x=S.elem[S.top[i]]; //栈顶元素的值通过x返回
return true;
}
(8)清空栈。
void makeEmpty(DblStack& S,int i)
{
if(i==0)
S.top[0]=S.bot[0]=-1;
else
S.top[1]=S.bot[1]=S.m;
}
4. 设以数组Q.elem[maxSize]存放循环队列的元素,同时以Q.rear和Q.length分别指不循环队列中的队尾位置和队列中所含元素的个数。试给出该循环队列的队空条件和队满条件,并写出相应的插入(enQueue)和删除(deQueue)元素的操作。
设该循环队列的结构定义如下:
#define maxSize 100
typedef struct
{
//循环队列的结构定义
int elem[maxSize]; //队列存储数组
int rear,length; //队列的队尾指针和队列长度
}SqQueue;
/*rear是实际的队尾位置,其队空条件和队满条件分别为Q-length==0和
Q.length==maxSize。*/
//该队列的插入和删除函数代码如下:
int enQueue(SqQueue& Q,int x)
{
//元素x存放到队列尾部。若进队成功,函数返回true,否则返回false
if(Q.length==maxSize)
return 0; //判断队列是否已满,满则出错
Q.rear=(Q.rear+1)%maxSize; //队尾指针进
Q.elem[Q.rear]=x; //进队列
++Q.length; //队列长度加
return 1;
}
int deQueue(SqQueue& Q,int& x)
{//从队列队头退出元素,由x返回。若退队成功,函数返回true,否则返回false
if(Q.length==0)
return 0; //判断队列是否为空,空则出错
--(Q.length); //队列长度减
x=Q.elem[(Q.rear-Q.length+1+maxSize)%maxSize];
//返回原队头元素值
return 1;
}
5. 循环队列采用一维数组作为它的存储表示,往往很难确定数组到底需要设置多少元素才够用。设置太多元素,可能造成浪费;设置太少元素,可能造成溢出。为此可以改写队列的结构定义以及队列的插入和删除算法,自动根据需要调整队列的存储数组大小。
(1)改写队列的结构定义,以满足元素动态增长的需要。
原循环队列定义如下:
#define maxSize
typedef struct
{
int data[maxSize];
int front; //队首指针
int rear; //队尾指针
}SqQueue;
(2)改写队列的插入(进队)函数,当队列满并需要插入新元素时将数组空间扩大一倍,使新元素得以插入。
(3)改写队列的删除(出队)函数,当队列元素少于数组空间的1/4时,将数组空间自动缩减一半。
本题采用牺牲一个单元以区分队空还是队满的循环队列结构。
(1)元素数组可以动态增长的循环队列结构定义如下:
typedef struct
{
//循环队列的结构定义
int *data; //因为数组长度会变,所以要用指针,以便动态申请
int front,rear; //队列的队尾指针和队列长度
int maxSize; //因为动态申请,所以将数组长度由常量改为变量
}SqQueue;
(2)这里假定进队列的方式是先按rear指示的位置加元素,然后rear加1,数组大小为maxSize。
实现代码如下:
int enQueue(SqQueue& Q,int x)
{
if((Q.rear-Q.front+Q.maxSize)%Q.maxSize==Q.maxSize)
{ //队列已满
int newSize=2*Q.maxSize; //创建大一倍的数组
int *newArray=(int*)malloc(newSize *sizeof(int));
if(newArray==NULL)
return 0;
int newRear=Q.front,newFront=Q.front;
//向新数组传递数据
while(Q.rear!=Q.front)
{ //老队列不空
newArray[newRear ]=Q.data[Q.front];
Q.front=(Q.front+1) % Q.maxSize;
newRear=(newRear+1) % newSize;
}
free(Q.data);
Q.data=newArray;
Q.rear=newRear;
Q.front=newFront;
Q.maxSize=newSize;
}
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%Q.maxSize;
return 1;
}
(3)设front指示实际队尾的位置。实现代码如下:
int deQueue(SqQueue& Q,int& x)
{
int newSize=Q.maxSize/2;
int *newArray=(int*)malloc(newSize * sizeof(int));
if(newArray==NULL)
return 0;
int newRear=Q.front;
int newFront=Q.front;
while(Q.front !=Q.rear)
{
newArray[newRear]=Q.data[Q.front];
Q.front=(Q.front+1)%Q.maxSize;
newRear=(newRear+1)% newSize;
free(Q.data);
Q.data=newArray;
Q.rear=newRear;
Q.front=newFront;
Q.maxSize=newSize;
if(Q.rear==Q.front)
return 0;
x=Q.data[Q.rear];
Q.front=(Q.front+1)%Q.maxSize;
return 1;
}
6. 有一个n×n的对称矩阵A,将其上三角部分按列压缩存放于一个一维数组B中,A[0][0]存放于B[0]中。
B=[A
00,A
01,A
11,A
02,A
12,A
22,…,A
0(n-1),A
1(n-1),A
2(n-1),…,A
(n-1)(n-1)]
同时有两个函数:max(i,j)和min(i,j),分别计算下标i和j中的大者与小者。试利用它们给出求任意一个A[i][j]在B中存放位置的公式。
按对称性考虑,上三角部分按列压缩存放于一个一维数组B中,共有n(n+1)/2个元素,B[k]与A[i][j]的关系如下:

当i≤j时,max(i,j)=j,min(i,j)=i,此时:
k=(max(i,j)+1)max(i,j)/2+min(i,j)
当i>j时,max(i,j)=i,min(i,j)=j,此时:
k=(max(i,j)+1)max(i,j)/2+min(i,j)
综上所述,k=(max(i,j)+1)max(i,j)/2+min(i,j)。
7. 在将中缀表达式转换为相应的后缀表达式时,需要利用栈暂存某些操作符,现有一个中缀表达式:a+b*(c-d)+e/f#,请给出转换为后缀表达式时的处理过程及栈的相应变化(提示:运算符的优先级见下表,其中icp表示当前扫描到的运算符ch的优先级。该运算符进栈后的优先级为isp,字符“#”为表达式结束符)。
运算符的优先级
|
操作符 | # | ( | *,/ | +,- | ) |
isp | 0 | 1 | 5 | 4 | 6 |
icp | 0 | 6 | 4 | 2 | 1 |
|
中缀表达式:a+b*(c-d)+e/f#转换为后缀表达式时的处理过程及栈的相应变化见下表。isp是栈内优先(in stackpriority)数,icp是栈外优先(in coming priority)数。左括号“(”的栈外优先数最高,它一来到立即进栈,但当它进入栈中后,其栈内优先数变得极低,以便括号内的其他操作符进栈。其他操作符进入栈中后优先数都升1,体现在中缀表达式中相同优先级的操作符自左向右计算的要求,让位于栈顶的操作符先退栈并输出。操作符优先数相等的情况只出现在括号配对或栈底的“#”号与输入流最后的“#”号配对时。前者将连续退出位于栈顶的操作符,直到遇到“)”为止。然后将“)”退栈以对消括号,后者将结束算法。
处理过程及栈的相应变化
|
步序 |
扫描项 |
类型项 |
动作 |
栈的变化 |
输出 |
0 |
|
|
'#'进栈,读下一符号 |
# |
|
1 |
a |
操作数 |
直接输出,读下一符号 |
# |
a |
2 |
+ |
操作符 |
isp('#')<lcp('+'),进栈,读下一符号 |
#+ |
|
3 |
b |
操作数 |
直接输出,读下一符号 |
#+ |
b |
4 |
* |
操作符 |
isp('+')<lcp('*'),进栈,读下一符号 |
#+* |
|
5 |
( |
操作符 |
isp('+')<lcp('('),进栈,读下一符号 |
#+*( |
|
6 |
c |
操作数 |
直接输出,读下一符号 |
#+'( |
c |
7 |
- |
操作符 |
isp('(')<lcp('-'),进栈,读下一符号 |
#+*(- |
|
8 |
d |
操作数 |
直接输出,读下一符号 |
#+*(- |
d |
9 |
) |
操作符 |
isp('-')>lcp(')'),退栈,输出 |
#+*( |
- |
10 |
|
|
isp('(')==lcp(')'),退栈,读下一符号 |
#+* |
|
11 |
+ |
操作符 |
isp('+')>lcp('+'),退栈,输出 |
#+ |
* |
12 |
|
|
isp('+')>lcp('+'),退栈,输出 |
# |
+ |
13 |
|
|
isp('#')<lcp('+'),进栈,读下一符号 |
#+ |
|
14 |
e |
操作数 |
直接输出,读下一符号 |
#+ |
e |
15 |
/ |
操作符 |
isp('+')<lcp('/'),进栈,读下一符号 |
#+/ |
|
16 |
f |
操作数 |
直接输出,读下一符号 |
#+/ |
f |
17 |
# |
操作符 |
isp('/')>lcp('#'),退栈,输出 |
#+ |
/ |
18 |
|
|
jsp('+')>lcp('#'),退栈,输出 |
# |
+ |
19 |
|
|
isp('#')==lcp('#'),退栈,结束 |
|
|
8. 编写一个算法,将一个非负的十进制整数N转换为一个二进制数。
可以利用栈解决数制转换问题。例如,49
10=1·2
5+1·2
4+1·2
0=110001
2,其转换规则是:

式中,b
i表示二进制数的第i位上的数字。这样,十进制数N可以用长度为

位的二
进制数表示为

。若令

,则有
N=b
j2
j+b
j-12
j-1+…+b
12
1+b
02
0 =(b
j2
j-1+b
j-12
j-2+…+b
1)×2+b
0 =(N/2)×2+N%2('/'表示整除运算)
因此,可以先通过N%2求出b
0,然后令N=N/2,再对新的N做除2求模运算可求出b
1……如此重复直到某个N等于零结束。这个计算过程是从低位到高位逐个进行的,但输出过程是从高位到低位逐个打印的,为此需要利用栈来实现。代码如下:
int BaseTrans(int N)
{
int i,result=0;
int stack[maxSize],top=-1;
//定义并初始化栈,其中maxSize是已定义的常量,其大小足够处理本题中数据
while(N !=0)
{
i = N%2;
N = N/2;
stack[++top]=i;
}
while(top!=-1)
{
i=stack[top];
--top;
result=result * 10+i;
}
return result;
}
9. 试编写一个算法,检查一个程序中的花括号、方括号和圆括号是否配对,若全部配对则返回1,否则返回0。对于程序中出现的一对单引号或双引号内的字符不进行括号配对检查。39为单引号的ASCII值,34为双引号的ASCII值。
假设stack是已经定义的顺序栈结构体,可以直接调用的元素进栈、出栈、取栈顶元素、判断栈空的函数定义如下:
void Push(stack &S,char ch);
void Pop(stack &S,char &cla);
void getTop(stack S,char &ch);
int IsEmpty(staek S); //栈S空,返回1,否则返回0
在算法中,扫描程序中的每一个字符,当扫描到每个花括号、方括号、圆左括号时,令其进栈;当扫描到花括号、方括号、圆右括号时,检查栈顶是否为相应的左括号,若是则进行退栈处理;若不是则表明出现了语法错误,应返回0。当扫描到程序文件结尾时,若栈为空则表明没有发现括号配对错误,应返回1;否则表明栈中还有未配对的括号,应返回0。另外,对于一对单引号或双引号内的字符不进行括号配对检查。
由此可以写出以下代码:
int BracketsCheck(char f[])
{
//对由字符数组f所存字符串中的文本进行括号配对检查
stack S;char ch; //定义一个栈
char *p=f;
while(*p !='\0') //顺序扫描串中的每一个字符
{
if(*p==39) //单引号内字符不参与配对比较,过滤掉其中字符
while(*p !='\0' && *p !=39) //39为单引号的ASCII值
++p;
else if(*p !='\0' && *p==34) //双引号内字符不参与配对比较
while(*p !='\0' && *p !=34) //34为双引号的ASCII值
++p;
if(*p !'\0')
{
switch(*p)
{
case '{':
case '[':
case '(': Push(S,*p);
//出现左括号:'(','['和'('进栈
break;
case ')': getTop(S,ch);
if(ch=='{') //栈顶的左花括号出栈
Pop(S,ch);
else
return 0;
break;
case ']': getTop(S,ch);
if(ch=='[') //栈顶的左方括号出栈
Pop(S,ch);
else
return 0;
break;
case ')': getTop(S,ch);
if(ch=='(') //栈顶的左圆括号出栈
Pop(S,ch);
else
return 0;
}
++p;
}
if(IsEmpty(S))
return 1;
else
return 0;
}
}
10. 数学上常用的阶乘函数定义如下:

对应的求阶乘的递归算法代码如下:
long Factorial(long n) //因为阶乘结果往往很大,所以用long而不用int
{
if(n<=0) //终止递归的条件
return 1;
else
return n*Factorial(n-1); //递归步骤
}
试推导求n!时的计算次数。
可用递归方式计算。设当n=0时,计算时间复杂度为常数T(0)=d;当n>0时,按T(n)=T(n-1)+c(c为常数),则有
T(n)=T(n-1)+c
=T(n-2)+2×c
=T(n-3)+3×c

=T(1)+(n-1)×c
=T(0)+n×c
=n×c+d
11. 试推导当总盘数为n时的汉诺塔的移动次数。
描述汉诺塔问题的递归算法代码如下:
void Hanoi(int x,int y,int z,int n)
{/*代表将n个盘子分别从x移到z上,y做辅助柱。*/
if(n==1)
move(x,z); //n为1可以直接解决
else
{
Hanoi(x,z,y,n-1); //分别处理n-1个盘,从x移动到y上,z做辅助
move(x,z); //直接移动x上的一个盘到z上
Hanoi(y,x,z,n-1); //分别处理n-1个盘,从y移动到z上,x做辅助
}
}
设move()函数执行的移盘次数为常数1,则汉诺塔问题总的运算次数代码如下:
T(1)=1=2
1-1;
T(2)=2×T(1)+1=3=2
2-1;
T(3)=2×T(2)+1=2*3+1=7=2
3-1;

T(n)=2×T(n-1)+1=2
n-1
Legendre多项式定义如下:

12. 编写一个递归算法,计算该多项式的值。
递归算法可以根据函数的定义来编写。
float Legendre_(float x,int n)
{
if(n==0) return 1;
if(n==1) return x;
return
((2*n-1)*x*Legendre(x,n-1)-(n-1)*Legendre(x,n-2))/n;
}
13. 编写一个非递归算法,计算该多项式的值。
使用迭代法的非递归算法:从多项式的定义中可以看出,要求Legendre(x,n),必须先求Legendre(x,n-1)和Legendre(x,n-2),递归结束于Legendre(x,0)和Legendre(x,1)。只要用backone保存Legendre(x,n-1),用backtwo保存Legendre(x,n-2),即可求Legendre(x,n)。不需要使用栈编写非递归算法。用这种思路编写的非递归算法代码如下:
float Legendre(float x,int n)
{
float current,backone,backtwo;
int i;
if(n==0) return 1;
if(n==1) return x;
backone=x;backtwo=1;
for(i=2;i<=n; ++i)
{
current=((2*n-1)*x*backone-(n-1)*backtwo)/n;
backtwo=backone;
backone=current;
}
return current;
}
设有一个n×n的对称矩阵A。为了节约存储,可以只存对角线及对角线以上的元素,或者只存对角线或对角线以下的元素。前者称为上三角矩阵,后者称为下三角矩阵。把它们按行存放于一个一维数组B中,并称之为对称矩阵A的压缩存储方式。试问:14. 存放对称矩阵A上三角部分或下三角部分的一维数组B有多少元素?
B中元素个数是一个等差数列前n项和。数列首项为1,尾项为n。
元素个数:(1+n)×n/2个
15. 若在一维数组B中从0号位置开始存放,则对称矩阵A中的任意一个元素a
ij在只存上三角部分的情形下(如下面一维数组B的存储情况)应存于一维数组的什么下标位置?给出计算公式。
对称矩阵A:
只存A的上三角部分:
一维数组B:
a11 | a12 | … | a1n | a22 | … | a2n | … | ann |
当只存上三角部分时,若i≤j,则矩阵元素A[i][j]在第i行,它前面有i-1行(矩阵从第1行1列开始计算),第1行有n个元素,第2行有n-1个元素……,第i-1行有n-i+2个元素。在第i行中,从对角线算起,第j号元素前面有j-i个元素,因此矩阵元素A[i][j]在数组B中的存放位置为
n+(n-1)+(n-2)+…+(n-i+2)+j-i=(2n-i)×(i-1)/2+j-1
若i>j,矩阵元素A[i][j]在数组B中没有存放,可以找它的对称元素A[j][i]。在数组B的第(2n-j)×(j-1)/2+i-1位置中找到。
注意,有的习题要求矩阵从第0行0列开始存放,数组B从0号位置开始存放,则矩阵元素A[i][j]在数组B中的存放位置如下:
当i≤j时,矩阵元素A[i][j]在数组B中的存放位置为n+(n-1)+…+(n-i+1)=(2n-i+1)×i/2+j-i=(2n-i-1)×i/2+j。
当i>j时,找对称元素,矩阵元素A[i][j]在数组B中的存放位置=(2n-j-1)×j/2+i。