61. int Length ( ) const { return last+1; } //返回元素的个数
int Find (T & x ) const; //返回元素x在表中的位置
void Insert (T & x, int i ); //在位置i插入元素x
int Remove (T & x ); //删除值为x的元素
int IsEmpty ( ) { return last ==-1; } //表空否
int IsFull ( ) { return last == MaxSize-1; }
T GetData ( int i ) { //取第i个表项的值
return data[i-1] };
void SetData ( int i, T & x) { //为第i个表项赋值
if (i >0 && i <= last+1) data[i-1] = x ;}
void input();
void output();
}
62. 顺序表部分公共操作的实现:
①构造函数
SeqList :: SeqList ( int sz ) {
//构造函数,通过指定sz,定义数组的长度
if ( sz > 0 ) {
data = new T[sz];
if ( data != NULL ) {
MaxSize = sz; last = -1;}
else {cerr <<“存储分配错误!”<<endl;exit(1);}
}
} 设计思路:
若sz>0,则为数组申请空间:
①若申请成功,MaxSize=sz,last=-1
②若申请失败,则提示出错
64. int SeqList::Find ( T & x ) const {
//搜索函数:在表中从前向后顺序查找 x
int i = 0;
while ( i <= last && )
data[i] != x
i++;
if ( i > last ) return -1; else
return i+1;
}
设计思路:
① x与data[i]逐个循环比较,直到x=data[i]或i>last
② 若i>last,则没有找到x,否则返回i+1
65. 搜索成功:
n 1
ACN = pi ci
i 0
若搜索概率相等,则
1n1 1
ACN = ( i 1) (1 2 n)
ni0 n
1 (1 n) n 1 n
n 2 2
搜索不成功 数据比较 n 次
算法时间复杂度: O(n)
71. 考虑移动元素的平均情况:
假设在第 i (0<=i<=n)个元素位置插入的
概率为 pi ,则在线性表中插入一个元素所需
移动元素次数的期望值为:
n
Eis pi (n i )
i 0
若假定在线性表中任何一个位置上进行插入
的概率都是相等的,则移动元素的期望值为:
n
1 n
Eis (n i)
n 1i 0 2
78. 求集合的“并”集
void Union ( SeqList &LA, SeqList LB ) {
int n = LA.Length ( );
int m = LB.Length ( );
for ( int i = 1; i <= m; i++ ) {
T x = LB.GetData(i);
//在B中取一元素
int k = LA.Find (x); //在A中搜索它
if ( k == -1 ) //若未找到插入它
{ LA.Insert (x,n++); }
}
}
时间复杂度:
O(LA.Length()×LB.Length())
80. 求“交”集
void Intersection(SeqList &LA, SeqList LB ) {
int n = LA.Length ( );
int m = LB.Length ( );
int i = 1;
while ( i <= n ) {
T x = LA.GetData (i);
//在LA中取一元素
int k = LB.Find (x); //在LB中搜索它
if ( k == -1 ) { LA.Remove (x); n--; }
else i++; //未找到在LA中删除它
}
}
90. #include <iostream.h>
#include <stdlib.h>
class List; //前视定义,否则友元无法定义
class LinkNode{ 链表结点类的定义
friend class List;
private:
LinkNode *link;
int data;
public:
LinkNode (LinkNode *ptr = NULL) {link=ptr;}
LinkNode(const int & item, LinkNode *ptr = NULL)
{ data=item;link=ptr;}
~LinkNode(){};
};
91. 单链表类的定义
class List {
private:
LinkNode *first; //指向头结点的头指针
public:
List () { first = new LinkNode ();}
//带头结点构造函数
List ( const int &x ) {
//不带头结点构造函数
first = new LinkNode ( x ); }
92. ~List (){makeEmpty(); delete first;} //析构函数
void MakeEmpty ( ); //链表置空
int Length ( ) const; //求链表长度
LinkNode * getHead() const {return first;}
LinkNode *Find ( int x );
LinkNode *Locate ( int i );
DataType GetData ( int i );
void SetData (int x,int i );
93. void Insert (int x, int i );
void Remove (int &x, int i );
int IsEmpty()const{
return(first->link==NULL? 1:0;}
void input(DataType endTag);
void output();
};
97. 求表长
int List::Length ( ) const {
LinkNode *p = first→link;
//检测指针p指示第一个结点
int count = 0;
while ( p != NULL ) { //逐个结点检测
count++; p = p→link;
}
return count;
}
98. ③在表中搜索数据x的结点:Find ( int x )
LinkNode * List::Find ( int x ){
LinkNode *p = first→link; //指针 p 指示第一个结点
while ( p != NULL && p→data != x )
p = p→link;
return p; // p 在搜索成功时返回找到的结点地址
// p 在搜索不成功时返回空值
} 思路:①指针p指向first->link
②当链表没有结束且结点的数
据不为x,
则p指向下一结点。
③返回p
99. ④定位函数,返回表中第i个数据的地址
LinkNode * List::Locate ( int i ){
if ( i < 0 ) return NULL;
LinkNode *p = first; int j = 0;
while ( p != NULL && j < i ) // j = i 停
{ p = p→link; j++; }
return p;
} 思路:①i<0,返回空
② 指针p指向first ,j=0
③当链表没有结束且结点的序号不为i,
则p指向下一结点,j加1。
④返回p
100. ⑤取出链表中第i个元素的值
DataType List::GetData( int i ) {//提取第 i 个结点的值
LinkNode *p = Locate( i ); // p 指向链表第 i 个结点
return p->data;
}
教材上的程序和功能不完全一致p63
思路:①p指针定位到第i个元素
② 返回p指针的数据域
101. ⑥给链表中第i个元素赋值
void List::SetData(DataType x,int i ) {//给第 i 个结点赋值
if ( i <= 0 ) return;
LinkNode *p = Locate ( i ); // p 指向链表第 i 个结点
if (p!=NULL) p->data=x;
}
思路:① 若i<=0,返回
② p指针定位到第i个元素
③若p不为空,使指针的数据域为x
④返回
113. 循环链表的搜索算法
first 31 48 15 57
搜索15 p p 搜索成功
p
first 31 48 15 57
p p p p p
搜索25 搜索不成功
113
114. 循环链表的搜索算法
CircListNode * CircList::Find( DataType x )
{
//在链表中从头搜索其数据值为 x 的结点
CircListNode * p = first->link;
while ( p!= first && p->data != x )
p = p->link;
if ( p != first ) return p; //搜索成功
else return NULL; //搜索不成功
}
first 31 48 15 57
搜索15
p
119. 求解Josephus问题的算法
#include <iostream.h>
#include ―CircList.h‖
void Josephus(CircList & Js, int n, int m) {
CircLinkNode *p = Js.getHead();
*pre = NULL;
int i, j;
for ( i = 0; i < n-1; i++ ) { //执行n-1次
for ( j = 1; j < m; j++) //数m-1个人
{ pre = p; p = p->link; }
cout << ―出列的人是” << p->data << endl;
119
120. pre->link = p->link; delete p; //删去
p = pre->link;
}
};
void main() {
CircList clist;
int i, n m;
cout << ―输入游戏者人数和报数间隔 : ‖;
cin >> n >> m;
for (i = 1; i <= n; i++ ) clist.insert(i, i); //约瑟夫环
Josephus(clist, n, m); //解决约瑟夫问题
}
120
122. first first
非空表 空表
结点指向
p == p->lLink->rLink == p->rLink->lLink
rLink lLink
p->lLink p p->rLink
122
123. 双向循环链表的搜索算法
DblNode *DblList::Find (DataType x, int d) {
//在双向循环链表中寻找其值等于x的结点, //按d确定
搜索方向,d为0,向左搜索, d为1,向右搜索
DblNode *p= (d == 0)?first->lLink : first->rLink;
while ( p != first && p->data != x )
p = (d == 0) ? p->lLink : p->rLink;
if ( p != first ) return p; //搜索成功
else return NULL; //搜索失败
};
123
124. 双向循环链表的插入算法
first 31 48 15
后插入25 p
first 31 48 25 15
p newNode
newNode->rLink = p->rLink;
p->rLink = newNode;
newNode->rLink->lLink = newNode;
newNode->lLink = p;
125. 双向循环链表的删除算法
first 31 48 15 非空表
删除48 p
p->rLink->lLink = p->lLink;
p->lLink->rLink = p->rLink;
125
126. 2.5 单链表的应用
多项式
(Polynomial)
Pn ( x ) a0 a1 x a2 x 2 an x n
n
i
ai x
i 0
n阶多项式 Pn(x) 有 n+1 项。
系数 a0, a1, a2, …, an
指数 0, 1, 2, …, n。按升幂排列
126
127. 2.5.1 多项式的存储表示
第一种: 静态数组表示
在类的私有域中定义多项式的数据成员:
private:
int degree;
float coef [maxDegree+1];
则Pn(x)可以表示为:
pl.degree = n, pl.coef[i] = ai, 0 i n
0 1 2 degree maxDegree
coef a0 a1 a2 …… an ………
n
127
129. 第三种:只存储非零系数项的系数和指数
0 1 2 i m
coef a0 a1 a2 …… ai …… am
exp e0 e1 e2 …… ei …… em
struct term { //多项式的项定义
float coef; //系数
int exp; //指数
};
static term termArray[maxTerms]; //项数组
static int free, maxTerms; //当前空闲位置指针
129
159. 一般地,设有 n 个元素按序号1, 2, …, n
进栈,轮流让 1在出栈序列的第1, 第2, …
第n位,则可能的出栈序列数为:
n -1
mi * mn i 1 m0 * mn 1 m1 * m n 2 mn 1 * m0
i 0
推导结果为:
n 1
1 n
n 1 C2n
mi * mn i 1
i 0
183
168. 例如: Exp = a b + (c d / e) f
前缀式: + ab c/def
中缀式: a b + (c d / e) f
后缀式: ab cde/ f +
结论:
1)操作数之间的相对次序不变;
2)运算符的相对次序不同;
3)中缀式有操作符的优先级问题,还有可加括号改
变运算顺序的问题,所以编译程序一般不使用中缀表
示处理表达式。
169. 例如: Exp = a b + (c d / e) f
前缀式: + ab c/def
中缀式: a b + (c d / e) f
后缀式: ab cde/ f +
结论:
4)前缀式的运算规则为:
连续出现的两个操作数和在它们之前且紧靠它们
的运算符构成一个最小表达式;
5)后缀式的运算规则为:
运算符在式中出现的顺序恰为表达式的运算顺序;
每个运算符和在它之前出现且紧靠它的两个操作数构成
一个最小表达式。
174. ④读字符串并求后缀表达式的值
void Calculator::Run{
char ch; double newoperand;
while(cin.get(ch),ch!=„#‟){
switch(ch){
case „+‟:case „-‟: case „*‟: case „/‟:
DoOperator(ch); break;
default:cin.putback(ch);
cin>>newOperand;
AddOperand(newOperand); }
}
S.Pop(newoperand ); cout<< newoperand;
};
175. ⑤取两个操作数,根据操作符op计算
void Calculator:: DoOperator(char op){
double left,right,value; bool result;
result = get2Operands(left, right)
if (result)
switch(op){
case „+‟:value=left+right;S.Push(value);break;
case „-‟: value=left-right;S.Push(value);break;
case „*‟: value=left*right;S.Push(value);break;
176. case „/‟: if (right==0.0){
cerr<<“Divide by 0!”<<endl; Clear();}
else{value=left/right;S.Push(value);}
break;
}
else Clear();
};
void main(){
Calculator CALC(20);
CALC.Run();
}
177. 3.如何将中缀表示→转后缀表示?
• 先对中缀表达式按运算优先次序加上括号,再
把操作符后移到右括号的后面并以就近移动为
原则,最后将所有括号消去。
• 如中缀表示 (A+B)*D-E/(F+A*D)+C,其转换为
后缀表达式的过程如下:
( (( (A+ B ) * D ) – ( E / ( F+ (A* D ) )) ) + C )
后缀表示 A B + D * E F A D * + / - C +
201
178. 如何将中缀表示→转前缀表示?
• 先对中缀表达式按运算优先次序通统加上括
号,再把操作符前移到左括号前并以就近移
动为原则,最后将所有括号消去。
• 如中缀表示 (A+B)*D-E/(F+A*D)+C,其转
换为前缀表达式的过程如下:
( ( ( (A+ B ) * D ) – ( E / ( F+ (A* D ) ) ) ) + C )
前缀表示 + - * + A B D / E + F * A D C
202
196. 3. 问题的解法是递归的
• 汉诺塔(Tower of Hanoi)问题的解法:
如果 n = 1,则将这一个盘子直接从 A 柱移
到 C 柱上。否则,执行以下三步:
① 用 C 柱做过渡,将 A 柱上的 (n-1) 个盘
子移到 B 柱上;
② 将 A 柱上最后一个盘子直接移到 C 柱上;
③ 用 A 柱做过渡,将 B 柱上的 (n-1) 个盘
子移到 C 柱上。
220
197. • 解决方法:
n=1时,直接把圆盘从A移到C
– n>1时,
– ①先把上面n-1个圆盘从A移到B
②然后将n号盘从A移到C
– ③再将n-1个盘从B移到C。
– 即把求解n个圆盘的Hanoi问题转化为求解n-1个圆盘的
Hanoi问题,依次类推,直至转化成只有一个圆盘的Hanoi
问题
– 执行情况:
» 递归工作栈保存内容:形参n,x,y,z和返回地址
» 返回地址用行编号表示
n x y z 返回地址
198. main()
{ int m;
printf("Input number of disks:‖);
scanf("%d",&m);
hanoi(m,'A','B','C');
(0) }
void hanoi(int n,char x,char y,char z)
(1) {
(2) if(n==1)
(3) move(1,x,z);
(4) else{
(5) hanoi(n-1,x,z,y);
(6) move(n,x,z);
(7) hanoi(n-1,y,x,z);
(8) }
(9) }
213. 3.3.2 队列的数组存储表示 ─顺序队
列
队列的进队和出队
A
front rear 空队列 front rear A进队
A B A B C D
front rear B进队 front rear C, D进队
B C D C D
front rear A退队 front rear B退队 假溢出
C D E F G C D E F G
front rear E,F,G进队 front rear H进队,溢出
238