




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、3.1 栈的类型定义栈的类型定义3.2 利用栈实现表达式求值利用栈实现表达式求值3.4 队列队列3.3 栈与递归栈与递归3.5 数组数组3.6 特殊矩阵的压缩存储特殊矩阵的压缩存储栈和队列是限定插入和删除只能插入和删除只能在表的“端点端点”进行的线性表。 线性表线性表 栈栈 队列队列Insert(L, i, x) Insert(S, n+1, x) Insert(Q, n+1, x) 1in+1 Delete(L, i) Delete(S, n) Delete(Q, 1) 1in栈和队列是两种常用的数据类型栈和队列是两种常用的数据类型1234栈和队列是限定插入和删除只能插入和删除只能在表的“端
2、点端点”进行的线性表。 3.1.1 栈的定义栈的定义 堆栈是一种只允许在堆栈是一种只允许在表的一端进表的一端进行插入和删除运算行插入和删除运算的线性表;的线性表; 允许进行运算的一端称为允许进行运算的一端称为栈顶栈顶,另一端则称为另一端则称为栈底栈底; 当表中没有元素时,称为当表中没有元素时,称为空栈空栈; 堆栈的插入运算简称为堆栈的插入运算简称为入栈或进入栈或进栈栈,删除运算简称为,删除运算简称为出栈或退栈出栈或退栈。出栈出栈进栈进栈栈的示意图栈的示意图栈顶栈顶栈底栈底a an na a2 2a a1 1 堆栈的特点堆栈的特点出栈出栈进栈进栈栈的特点栈的特点后进先出后进先出第一个进栈的元素在
3、栈底第一个进栈的元素在栈底最后一个进栈的元素在栈顶最后一个进栈的元素在栈顶第一个出栈的元素为栈顶元素第一个出栈的元素为栈顶元素最后一个出栈的元素为栈底元最后一个出栈的元素为栈底元素素栈的示意图栈的示意图栈顶栈顶栈底栈底a an na a2 2a a1 1a1a2a3a4a5a6insert xiDelete xjinsertdelete栈的实例栈的实例实例:装网球的纸筒、子弹夹实例:装网球的纸筒、子弹夹 ,羊肉串,货栈,羊肉串,货栈3.1 栈的抽象数据类型定义栈的抽象数据类型定义 ADT Stack 数据对象数据对象: D ai | ai ElemSet, i=1,2,.,n, n0 数据关系
4、数据关系: R1 | ai-1, aiD, i=2,.,n 约定an 端为栈顶,a1 端为栈底。 基本操作:基本操作: ADT StackInitStack(Stack & S)DestroyStack(Stack &S)ClearStack(const Stack &S)StackEmpty(const Stack &S)StackLength(const Stack& S)GetTop(const Stack &S, &e)Push(Stack &S, e)Pop(Stack &S, &e)StackTravers(const Stack &S, visit()栈类型的实现栈类型的实现顺序
5、栈顺序栈链链 栈栈顺序栈的实现顺序栈的实现 和顺序表类似,对顺序栈的存储也是利和顺序表类似,对顺序栈的存储也是利用一组连续的存储单元依次存放自栈底用一组连续的存储单元依次存放自栈底到栈顶的元素,同时附设指针到栈顶的元素,同时附设指针toptop指示栈指示栈顶元素在顺序栈中的位置顶元素在顺序栈中的位置。由于栈在使用过程中所需最大空间的大小很难由于栈在使用过程中所需最大空间的大小很难估计,因此,在初始化设空栈时不应限定栈的估计,因此,在初始化设空栈时不应限定栈的最大容量。一般,先分配一个基本容量,然后最大容量。一般,先分配一个基本容量,然后在应用过程中,当栈的空间不够使用时再逐段在应用过程中,当栈
6、的空间不够使用时再逐段扩大。扩大。栈的数组表示栈的数组表示 顺序栈顺序栈0 1 2 3 4 5 6 7 8 9 maxSize-1top()elem#define initSize 100 /栈空间初始大小栈空间初始大小#define increament 20 /栈空间扩充增量栈空间扩充增量typedef struct /顺序栈定义顺序栈定义 SElemType *elem; /栈数组栈数组 int top, maxSize; /栈顶指针及栈大小栈顶指针及栈大小 SeqStack; top空栈toptoptoptoptopa 进栈b 进栈aababcdee 进栈abcdef 进栈溢出abde
7、e 退栈c 顺序栈的示意图顺序栈的示意图topc 退栈b 退栈abaa 退栈空栈topabdd 退栈ctopabctoptop栈顶指针指示实际栈顶位置即最后加入新元素的位置void InitStack (SeqStack& S) /初始化初始化 S.elem = new SElemTypeInitSize; if (S.elem = NULL) printf(“存储分配失败存储分配失败!n”); exit(1); S.top = -1; S.maxSize = InitSize; bool StackEmpty(const SeqStack& S) /判断栈是否空?空则返回判断栈是否空?空则返
8、回1,否则返回,否则返回0 return S.top = -1; bool Pop(SeqStack& S, SElemType& x) /若栈空返回若栈空返回0, 否则栈顶元素退出到否则栈顶元素退出到x并返回并返回1 if (StackEmpty(S) return 0; x = S.elemS.top; S.top-; return 1;bool getTop(SeqStack& S, SElemType& x) /若栈空返回若栈空返回0, 否则栈顶元素读到否则栈顶元素读到x并返回并返回1 if (StackEmpty(S) return 0; x = S.elemS.top; retur
9、n 1;bool StackFull(const SeqStack& S) /判断栈是否满?满则返回判断栈是否满?满则返回1,否则返回,否则返回0 return S.top = S.maxSize-1; void Push(SeqStack& S, SElemType x) /若栈满返回若栈满返回0, 否则否则新元素新元素 x 进栈并返回进栈并返回1 if (StackFull(S) OverFlow(S); /栈满溢出处理栈满溢出处理 S.top+; S.elemS.top = x; /加入新元素加入新元素void OverFlow(SeqStack& S) /栈满处理 int newSiz
10、e = S.maxSize+StackIncrement; SElemType *newS = new SElemTypenewSize; if (newS = NULL) printf(“数组创建失败数组创建失败!n”); exit(1); S.elem = newS; /新数组作为栈数组新数组作为栈数组 S.maxSize = newSize; /新数组大小新数组大小SElemType *src = S.elem, *obj = newS; for (int i = 0; i data = x; /结点赋值 p-link = S; S = p; /链入栈顶bool Pop ( LinkSt
11、ack& S, ElemType& x ) /退栈 if ( StackEmpty(S) ) return 0; StackNode * p = S; S = p-link; x = p-data; /摘下原栈顶 delete p; return 1; /释放原栈顶结点 bool getTop(LinkStack& S, ElemType& x) if ( StackEmpty(S) ) return 0; x = S-data; return 1; 3.3 栈的应用举例栈的应用举例例一、例一、 数制转换数制转换例二、例二、 括号匹配的检验括号匹配的检验例三、表达式求值例三、表达式求值例四、例
12、四、 用栈实现递归用栈实现递归 例一、例一、 数制转换数制转换将十进制数转换为其他进制数将十进制数转换为其他进制数的基本方法是辗转相除法。的基本方法是辗转相除法。 void conversion () / conversionSeqStack S; InitStack(S); scanf(“%d”,n);while (n) Push(S, n % 8); n= n/8; (159)10=(237)8while (!StackEmpty(S) Pop(S,e); printf ( %d, e );3 7 余 7余 3余 2Top=-1top7top73top732运算次
13、序和输出次序相反运算次序和输出次序相反例二、例二、 括号匹配的检验括号匹配的检验每个右括号将与每个右括号将与最近遇到最近遇到的未匹配的未匹配的左括号相匹配,可能出现的的左括号相匹配,可能出现的不匹不匹配配的情况的情况: :(1) 到来的右括弧不是最“期待”的;例如:下列括号序列:例如:下列括号序列: ( ) 1 2 3 4 1 2 3 4例如:下列括号序列:例如:下列括号序列: ( ( ) ) 1 2 3 4 5 6 1 2 3 4 5 6 (2) 到来的右括弧是“不速之客”;(3) 直到结束,也没有到来所“期待”的右括弧;例如:下列括号序列:例如:下列括号序列: ( ) ( ) 1 2 3
14、4 5 1 2 3 4 5 算法的设计思想:算法的设计思想:1)凡出现左括弧左括弧,则进栈进栈;2)凡出现右括弧右括弧,首先检查栈是否空 若栈空栈空,则表明该“右括弧右括弧”多余多余 否则和栈顶元素和栈顶元素比较, 若相匹配相匹配,则“左括弧出栈左括弧出栈” 否则表明不匹配不匹配3)表达式表达式检验结束时结束时, 若栈空栈空,则表明表达式中匹配正确匹配正确 否则表明“左括弧左括弧”有余有余从左到右扫描一个字符串:status matching(char *exp) int state=1int state=1,i=0; i=0; LinkStack s; /LinkStack s; /用链式栈
15、存储左括号用链式栈存储左括号while (istrlen(exp) & state) switch (expi) case : case : case ( : /左括号进栈左括号进栈 case”)”: if (StackEmpty(S)&state) return 0; /匹配成功匹配成功else return -1; /else return -1; /匹配失败匹配失败 push(s,expi); i+; break; if(! StackEmpty(s)&GetTop(s)=( ) pop(S,e); i+; else state = 0; break; 1 1)问题的提出)问题的提出从键
16、盘一次性输入一串算术表达式,给出计算结果。从键盘一次性输入一串算术表达式,给出计算结果。2+32+3* *(5-4)=5(5-4)=5 例三例三 算术表达式求值算术表达式求值2 2)表达式的构成)表达式的构成 操作数操作数+ +运算符运算符+ +界符界符常数常数+ +、- -、* *、/ /( )( )、# #表达式中相邻两个操作符的计算次序为: 优先级高的先计算; 优先级相同的自左向右计算;a) 当使用括号时从最内层括号开始计算。 表达式的三种表示方法:表达式的三种表示方法:设设 Exp = S1 + OP + S2则称则称 OP + S1 + S2 为前缀表示法前缀表示法 S1 + OP
17、+ S2 为中缀表示法中缀表示法 S1 + S2 + OP 为后缀表示法后缀表示法 例如:中缀式:a b + (c d / e) f后缀式: a b c d e / f + 结论结论:1)操作数之间的相对次序不变)操作数之间的相对次序不变;2)运算符的相对次序不同)运算符的相对次序不同;3)中缀式要保持正确的运算次序必须加括弧; 4)后缀式的运算规则后缀式的运算规则为: 运算符在式中出现的顺序恰为运算符在式中出现的顺序恰为 表达式的运算顺序表达式的运算顺序; 每个运算符和在它之前出现每个运算符和在它之前出现 且且 紧靠它的两个操作数构成一个最小紧靠它的两个操作数构成一个最小 表达式表达式;例如
18、:例如: a b c d e / f +a bd/ec-d/e(c-d/e) f算术表达式求值算法的设计思路:算术表达式求值算法的设计思路: 步骤步骤1: 将用户所输入的带有括号将用户所输入的带有括号的中缀表达式变为后缀表达式。的中缀表达式变为后缀表达式。步骤步骤2: 对后缀表达式求值。对后缀表达式求值。l如何从原表达式求得后缀式?如何从原表达式求得后缀式?每个运算符的运算次序要由它之后的一个运算符它之后的一个运算符来定,在后缀式中,优先数高的运算符领先于优先数低的运算符。分析 “原表达式” 和 “后缀式”中的运算符: :原表达式: : a + b c d / e f 后缀式: a b c +
19、 d e / f 使用栈可将表达式的中缀表示转换成它的前缀表示和后缀表示。为了实现这种转换,需要考虑各操作符的优先级。算符优先关系表算符优先关系表 表达式中任何相邻运算符表达式中任何相邻运算符 1 1、 2 2 的优先关系有:的优先关系有: 1 1 2 2: 1 1的优先级的优先级 高于高于 2 2+ 2 1 - -* */( () )#+ - - * * / ( ( ) ) # = 注注:1 1、2 2是相邻算符,是相邻算符,1 1在左,在左,2 2在右在右从原表达式求得后缀式的步骤为:从原表达式求得后缀式的步骤为:1) 设立暂存运算符的栈栈;2) 设表达式的结束符为“#”, 予设运算符栈的
20、栈底为“#”3) 若当前字符是操作数, 则直接发送给后缀式;4) 若当前扫描位置的当前扫描位置的运算符的优先优先数高数高于栈顶运算符,则进栈;5) 否则,退出栈顶运算符发送给后缀式; 6) “(” 对它之前后的运算符起隔离作用,“)”可视为自相应左括弧开始的表达式的结束符。convert_postfix1void transform(char suffix , char exp ) InitStack(S); Push(S, #); p = exp; ch = *p; while (!StackEmpty(S) if (!IN(ch, OP) Pass( Suffix, ch); else i
21、f ( ch!= # ) p+; ch = *p; else Pop(S, ch); Pass(Suffix, ch); / while / CrtExptree P P指向当前扫描位置指向当前扫描位置switch (ch) case ( : Push(S, ch); break; case ) : Pop(S, c); while (c!= ( ) Pass( Suffix, c); Pop(S, c) break; defult : while(Gettop(S, c) & ( precede(c,ch) Pass( Suffix, c); Pop(S, c); if ( ch!= # )
22、 Push( S, ch); break; / switch栈顶元素的优先级高于当栈顶元素的优先级高于当前扫描字符的优先级前扫描字符的优先级如何从后缀式求值?如何从后缀式求值?先找运算符,先找运算符, 再找操作数再找操作数1) 设立暂存后缀表达式的操作数操作数的栈栈2) 扫描后缀表达式,当遇到操作数操作数时,将其存入栈中.3)当遇到操作符操作符时,从栈中弹出两个栈顶元素,执行算数运算后将结果压入栈中.如何利用栈计算后缀表达式的值?如何利用栈计算后缀表达式的值?stack_calculate_postfix多个函数嵌套调用的规则是:此时的内存管理实行“栈式管理栈式管理”后调用先返回后调用先返回
23、!void main( ) void a( ) void b( ) a( ); b( ); /main / a / bMain的数据区函数a的数据区函数b的数据区例五、利用栈实现递归例五、利用栈实现递归求解阶乘函数的递归算法求解阶乘函数的递归算法long Factorial ( long n ) if ( n = 0 ) return 1; else return n * Factorial (n-1);时时当当时时当当 1 ,)!1( 0 , 1!nnnnn分析递归函数的执行过程1. void print(int w)2. 3. if ( w=0)4. return; 5. else6. p
24、rint(w-1);7. for(int i=1;i=w;+i)8. coutw“, “endl;9. 10 1,2,2,3,3,3,1. void main()2. int w=3;3. print(w);4. return;5. 运行结果?Main program4. return;print(w) w=3; 3print(2);Line=4, w=3topw2print(1);Line=7, w=2Line=4, w=3 topw1print(0);Line=7,w=1Line=7,w=2Line=4,w=3topw0Line=7,w=1Line=7,w=2Line=4,w=3topw(
25、3) output:2, 2Line=7, w=2Line=4, w=3top(4) output:1Line=7,w=1Line=7,w=2Line=4,w=3top(2) output:3, 3, 3 Line=4, w=3topreturnLine=7,w=1Line=7,w=2Line=4,w=3topLine=7,w=0end(1) return1. void print(int w)2. 3. if ( w=0)4. return; 5. else6. print(w-1); for(int i=1;i=w;+i) coutw“, “CC-BB-AB-CA-C(1,A,B, C)A
26、-B(1,C,A,B)(1,B,C,A)(1,C,A,C)(2,A,C,B)A-C(2,B,A,C)自顶向下,逐层分解递归算法的设计方法void recfunc ( int A , int n ) if(n=0) return; else cout An data = x ) printf printf (“%dn”, f -data ); ; else else Print ( f - link, x ); ; f f f f 递归找含x值的结点x递归过程改为非递归过程 递归过程简洁、易编、易懂。然而,递归过程效率低,重复计算多。 例如,定义一个计算斐波那契数列的递归函数Fib(n)如 F0
27、 = 0, F1 = 1, F2 = 1, F3 = 2, F4 = 3, F5 = 5, F6 = 8, 求解斐波那契数列的递归算法为:1n2),Fib(n1)Fib(n0,1nn,Fib(n)long Fib(long n) if ( n = 1 ) return n; else return Fib(n-1) + Fib(n-2); 重复计算多Fib(1)Fib(0)Fib(1)Fib(2)Fib(3)Fib(4)Fib(1)Fib(0)Fib(2)Fib(1)Fib(0)Fib(1)Fib(2)Fib(3)Fib(5)Fib(5)Fib(5)计算计算1 1次次, Fib(4), Fib
28、(4)计算计算1 1次次, Fib(3), Fib(3)计算计算2 2次次, Fib(2), Fib(2)计计算算3 3次次, Fib(1) , Fib(1) 计算计算5 5次次, Fib(0) , Fib(0) 计算计算3 3次。次。 改为非递归过程的目的是改为非递归过程的目的是提高效率提高效率。 单向递归单向递归和和尾递归尾递归可直接用可直接用迭代迭代实现其非实现其非递归过程,其他情形必须借助递归过程,其他情形必须借助栈栈实现非递实现非递归过程。归过程。 单向递归单向递归是指递归过程执行时虽然可能有是指递归过程执行时虽然可能有多个分支,但可以保存前面计算的结果以多个分支,但可以保存前面计算
29、的结果以供后面的语句使用。供后面的语句使用。 尾递归尾递归指程序中只有一个递归语句,且在指程序中只有一个递归语句,且在程序最后,这时递归栈保存的内容无需再程序最后,这时递归栈保存的内容无需再利用。利用。用迭代法实现斐波那契数列的计算:用迭代法实现斐波那契数列的计算:long FibIter ( long n ) if ( n = 1 ) return n; long a = 0, b = 1, c; for ( int i = 2; i = 0 ) printf ( “%d”, An ); n-; recfunc( A, n ); void sterfunc( int A , int n )
30、/非递归函数 while ( n = 0 ) printf ( “ %s ”, An ); n-; 尾递归: ADT Queue 数据对象:数据对象: Dai | aiElemSet, i=1,2,.,n, n0 数据关系:数据关系: R1 | ai-1, ai D, i=2,.,n 约定其中a1 端为队列头队列头, an 端为队列尾队列尾基本操作:基本操作:3.4 队列的队列的ADT ADT Queue队列的基本操作:队列的基本操作: InitQueue(Queue&Q)DestroyQueue(Queue&Q)QueueEmpty(Queue &Q)QueueLength(Queue &Q
31、)GetHead(QueueQ, DataType&e)ClearQueue(Queue&Q)DeQueue(Queue&Q, DataType&e )EnQueue(Queue&Q, DataType&e)QueueTravers(Queue &Q, visit()队列类型的实现队列类型的实现链队列链队列链式映象循环队列循环队列顺序映象#define MAXSIZE 100 /最大队列长度typedef struct QElemType elemmaxSize; / 静态分配存储空间int front; / 头指针,若队列不空, / 指向队列头元素int rear; / 尾指针,若队列不空,
32、指向 / 队列尾元素 的下一个位置下一个位置 SqQueue;循环队列循环队列顺序映象仍有空余,但新仍有空余,但新元素无法插入元素无法插入设想数组的存储空间是个设想数组的存储空间是个 环环 ,认定,认定“55的的下一个位置是下一个位置是00。Front 指向队列的第一个元素,rear指向队尾的下一个可插入位置实现:利用实现:利用“模模”运算运算入队:入队:Q.elemrear=e; Q.rear=(Q.rear+1)%MAXSIZE; 出队:出队:e=Q.basefront; Q.front=(Q.front+1)% MAXSIZE; 队满、队空判定条件队满、队空判定条件?012345rear
33、frontJ7J5J6012345frontJ4J9J8rearJ5J6J4012345rearfrontJ4,J5,J6出队出队J7,J8,J9入队入队队空:队空:front=rear解决方案:解决方案:1.另外设一个标志以区别队空、队满另外设一个标志以区别队空、队满2.少用一个元素空间:少用一个元素空间: 队空:队空:Q.front=Q.rear 队满:队满:(Q.rear+1)%M=Q.front队满:队满:front=rear 进行插入运算,必须先测试队满与否。进行插入运算,必须先测试队满与否。若队满,若队满,则调用相关算法处理有关溢出问题;否则,将则调用相关算法处理有关溢出问题;否则
34、,将队尾指针加队尾指针加1,然后将新元素插入到当前队尾指,然后将新元素插入到当前队尾指针所指的位置。针所指的位置。 删除队头元素,必须先测试队列是否为空。删除队头元素,必须先测试队列是否为空。若若队空,则调用相关算法处理有关信息;否则,队空,则调用相关算法处理有关信息;否则,删除队头元素删除队头元素(队头指针加队头指针加1),如果需要,可以,如果需要,可以把被删除元素保存起来。把被删除元素保存起来。Status EnQueue (SqQueue &Q, QElemType e) / 插入元素e为Q的新的队尾元素 if (Q.rear+1) % MAXSIZE = Q.front) return
35、 ERROR; /队列满 Q.baseQ.rear = e; Q.rear = (Q.rear+1) % MAXSIZE; return OK; Status DeQueue (SqQueue &Q, QElemType &e) / 若队列不空,则删除Q的队头元素, / 用e返回其值,并返回OK; 否则返回ERROR if (Q.front = Q.rear) return ERROR; e = Q.baseQ.front; Q.front = (Q.front+1) % MAXSIZE; return OK; typedef struct node / 结点类型结点类型 QElemType
36、data; struct Node *link; LinkNode, QueuePtr链队列链队列链式映象typedef struct / 链队列类型链队列类型 QueuePtr front; / 队头指针队头指针 QueuePtr rear; / 队尾指针队尾指针 LinkQueue;a1anQ.frontQ.frontQ.rear空队列空队列Q.rear Status InitQueue (LinkQueue &Q) / 构造一个空队列Q Q.front = Q.rear = new QNode; if (!Q.front) exit (OVERFLOW); /存储分配失败 Q.front
37、-next = NULL; return OK; Status EnQueue (LinkQueue &Q, QElemType e) / 插入元素e为Q的新的队尾元素 p = new QNode; if (!p) exit (OVERFLOW); /存储分配失败 p-data = e; p-link = NULL; Q.rear-link = p; Q.rear = p; return OK;a1anQ.frontQ.rearep Status DeQueue (LinkQueue &Q, QElemType &e) / 若队列不空,则删除Q的队头元素, /用 e 返回其值,并返回OK;否则
38、返回ERROR if (Q.front -link=null) return ERROR; p = Q.front-link; e = p-data; Q.front-link= p-link; /队头修改 delete (p); return OK;队列应用示例队列应用示例利用队列打印二项式展开式利用队列打印二项式展开式(a+b) n的系数,即计算的系数,即计算 n 行行杨辉三角的值杨辉三角的值第 1 行 1 1 第 2 行 1 2 1 第 3 行 1 3 3 1第 4 行 1 4 6 4 1二项式系数值(杨辉三角)设第 i-1行的值:(a0=0) a1.ai (ai+1=0)则第 i 行的
39、值:bj = aj-1+aj, j=1,2,i+100000000解题方法引入引入“循环队列循环队列”,则可以在第,则可以在第k k行元素行元素依次出队列打印时把下一行的元素预先放依次出队列打印时把下一行的元素预先放入队列,当第入队列,当第k k行元素全部出队列时,下行元素全部出队列时,下一行元素已经到了队头。一行元素已经到了队头。第5行的界符第4行的界符假设队列中已存有第假设队列中已存有第 k k 行的计算结果,为了行的计算结果,为了计算方便,在每行前添加一个计算方便,在每行前添加一个“0”0”作为作为行界行界值值。在计算第。在计算第 k+1 k+1 行之前,行之前,头指针指向第头指针指向第
40、 k k 行的行的“0”0”。尾指针指向第。尾指针指向第k+1k+1行的行的“0 0”的下的下一个位置一个位置计算杨辉三角的基本操作计算杨辉三角的基本操作do DeQueue(Q, s); / / s 为第为第 k k 行行 “ “左上方左上方”的值的值GetHead(Q, e); / / e 为第为第 k k 行行 “ “右上方右上方”的值的值coute;/ / 输出输出 e 的值的值 EnQueue(Q, s+e);/ / 第第 k+1 行的值入队列行的值入队列 while (e!=0); EnQueue(Q,0); /0作为第作为第k+2行的行界符行的行界符多维数组是一种非线性结构。其特
41、点是每一个数据元素可以有多个直接前驱和多个直接后继。mnmmnnnmaaaaaaaaaA.212222111211 数组特点数组特点 数组结构固定 数据元素同构 数组运算数组运算 给定一组下标,存取相应的数据元素 给定一组下标,修改数据元素的值( )( )( )( )( )( )( )( )( )多维数组的存储和表示多维数组的存储和表示数组的类型特点数组的类型特点:1) 只有引用型操作,没有加工型操作;2) 数组是多维的结构,而存储空间是 一个一维的结构。3)多维数组实际上是用一维数组来存储的,只要能计算出多维数组中数组元素在相应一维数组中的位置,就可以据此直接存取相应数据元素。 按行序为主序
42、存放按行序为主序存放01n-1m-1*n-1n am-1,n-1 . am-1,1 am-1,0 . a1,n-1 . a1,1 a1,0 a0,n-1 . a0,1 a0,0 a0,0 a0,1 . a0,n-1 a1,0 a1,1 . a1,n-1 am-1,0 am-1,1 . am-1n -1 .Loc(aij)=Loc(a0,0)+i*n+j*l L 按列序为主序存放按列序为主序存放01m-1m-1*n-1m am-1,n-1 . a1,n-1 a0,n-1 . am-1,1 . a1,1 a0,1 am-1,0 . a1,0 a0,0 a0,0 a0,1 . a0,n-1 a1,0
43、 a1,1 . a1,n-1 am-1,0 am-1,1 . am-1n -1 .Loc(aij)=Loc(a0,0)+j*m+i*LL1) 非零元的分布有一定规律非零元的分布有一定规律 非零元在矩阵中的分布有一定规则 例如: 三角矩阵 对角矩阵2) 随机稀疏矩阵随机稀疏矩阵 非零元在矩阵中随机出现有两类特殊矩阵有两类特殊矩阵:特殊矩阵的压缩存储特殊矩阵的压缩存储对称矩阵的压缩存储 设有一个设有一个 n n n n 的矩阵的矩阵 A A。如果在。如果在在矩阵中,在矩阵中,a aij ij = a= aji ji,则此矩阵是对称矩阵,则此矩阵是对称矩阵。若只保存对称矩阵的对角线和对角线以上若只保
44、存对称矩阵的对角线和对角线以上 ( (下下) ) 的元素,则称此为对称矩阵的压缩存储。的元素,则称此为对称矩阵的压缩存储。11nn12n11n10n12n22212011n12111010n020100aaaaaaaaaaaaaaaaA11nn12n11n10n12n22212011n12111010n020100aaaaaaaaaaaaaaaa 若只存对角线及对角线以上的元素,称为上三若只存对角线及对角线以上的元素,称为上三角矩阵;若只存对角线或对角线以下的元素,角矩阵;若只存对角线或对角线以下的元素,称之为下三角矩阵。称之为下三角矩阵。下三角矩阵上上三三角角矩矩阵阵 把它们按行存放于一个一
45、维数组把它们按行存放于一个一维数组 B B 中,称中,称之为对称矩阵之为对称矩阵 A A 的压缩存储方式。的压缩存储方式。 数组数组 B B 共有共有 n+(n-1)+n+(n-1)+1 = +1 = n n* *(n+1)/2 (n+1)/2 个个元素。元素。11nn12n11n10n12n22212011n12111010n020100aaaaaaaaaaaaaaaa11nn12n11n10n12n22212011n12111010n020100aaaaaaaaaaaaaaaa下下三三角角矩矩阵阵B a00 a10 a11 a20 a21 a22 a30 a31 a32 an-1n-1 0
46、 1 2 3 4 5 6 7 8 n(n+1)/2-1 若若 ijij, , 数组元素数组元素AijAij在数组在数组B B中的存放位置为中的存放位置为 1 + 2 + + i + j = (i + 1)* i / 2 + j前前i-1行行元素总数元素总数第第i行第行第j个个元素前元素个数元素前元素个数反过来,反过来,若已知某矩阵元素位于数组若已知某矩阵元素位于数组 B B 的第的第 k k 个个位置,可寻找满足位置,可寻找满足 i (i + 1) / 2i (i + 1) / 2 k k (i + 1) (i + 1)* *(i + 2) / 2(i + 2) / 2的的 i i, , i
47、i即为即为该元素的行号。该元素的行号。 j = k - i j = k - i * * (i + 1) / 2 (i + 1) / 2此即为该元素的列号。此即为该元素的列号。 例,当例,当 k = 8k = 8, , 3 3* *4 / 2 = 4 / 2 = 6 6 k k 4 4* *5 / 2 =5 / 2 =1010,取,取 i = 3i = 3。则则 j = 8 - 3j = 8 - 3* *4 / 2 = 24 / 2 = 2。若若 i ij j,数组元素,数组元素 Aij Aij 在矩阵的上三角部分在矩阵的上三角部分, , 在在数组数组 B B 中没有存放,可以找它的对称元素中没
48、有存放,可以找它的对称元素Aji = j Aji = j * *( j +1 ) / 2 + i( j +1 ) / 2 + i 第i行首元素的位置第i+1行首元素的i i位置若若 ijij,数组元素,数组元素AijAij在数组在数组B B中的存放位置为中的存放位置为n + (n-1) + (n-2) + + (n-i+1) + j-i33323130232221201312111003020100aaaaaaaaaaaaaaaa上上三三角角矩矩阵阵B a00 a01 a02 a03 a11 a12 a13 a22 a23 a33 0 1 2 3 4 5 6 7 8 9n = 4前前i-1行行
49、元素总数元素总数 若若 ijij,数组元素,数组元素AijAij在数组在数组B B中的存放中的存放位置为位置为 n + (n-1) + (n-2) + n + (n-1) + (n-2) + + (n-i+1) + j-i = + (n-i+1) + j-i = = (2 = (2* *n-i+1) n-i+1) * * i / 2 + j-i = i / 2 + j-i = = (2(2* *n-i-1) n-i-1) * * i / 2 + j i / 2 + j 若若i ij j,数组元素,数组元素AijAij在矩阵的下三角部在矩阵的下三角部分,在数组分,在数组 B B 中没有存放。因此
50、,找它的中没有存放。因此,找它的对称元素对称元素AjiAji。AjiAji在数组在数组 B B 的第的第 (2(2* *n-j-1) n-j-1) * * j / 2 + i j / 2 + i 的位置中找到。的位置中找到。三对角矩阵的压缩存储三对角矩阵的压缩存储11nn21nn12nn22nn32nn2322211211100100aa0000aaa00000aaa0000aaa0000aaAB a00 a01 a10 a11 a12 a21 a22 a23 an-1n-2 an-1n-1 0 1 2 3 4 5 6 7 8 9 10第一行第二行第n行第三行只有主对角线及其上 下最临近的两条
51、对角线上的元素不为0。总共有3n-2个非零元素。 将三对角矩阵A中三条对角线上的元素按行存放在一维数组 B 中,且a00存放于B0。 在三条对角线上的元素aij 满足 0 i n-1, i-1 j i+1 在一维数组 B 中 Aij 在第 i 行,它前面有 3*i-1 个非零元素, 在本行中第 j 列前面有 j-(i-1)个元素,所以元素 Aij 在 B 中位置为: k =3i-1+j-(i-1)= 2i + j定义:非零元较零元少,且分布没有定义:非零元较零元少,且分布没有一定规律的矩阵一定规律的矩阵. 2) 2) 随机稀疏矩阵随机稀疏矩阵nmt假设假设 m m 行行 n n 列列的矩阵含的
52、矩阵含t t个非零元素个非零元素,则称则称为为稀疏因子稀疏因子通常认为通常认为 0.05 0.05 的矩阵为稀疏矩阵的矩阵为稀疏矩阵 以常规方法,即以一维数组表示以常规方法,即以一维数组表示高阶的稀疏矩阵时产生的问题高阶的稀疏矩阵时产生的问题:1) 零值元素占了很大空间零值元素占了很大空间;2) 计算中进行了很多和零值的运算,计算中进行了很多和零值的运算, 遇除法,还需判别除数是否为零遇除法,还需判别除数是否为零;1) 尽可能少存或不存零值元素尽可能少存或不存零值元素;解决问题的原则解决问题的原则:2) 尽可能减少没有实际意义的运算尽可能减少没有实际意义的运算;3) 操作方便操作方便; 即即:
53、 能尽可能快地找到能尽可能快地找到 与下标值与下标值 (i, j) 对应的元素对应的元素; 能尽可能快地找到能尽可能快地找到 同一行或同一列的非零值元同一行或同一列的非零值元;随机稀疏矩阵的压缩存储方法随机稀疏矩阵的压缩存储方法:一、三元组顺序表一、三元组顺序表二、行逻辑联接的顺序表二、行逻辑联接的顺序表三、三、 十字链表十字链表三元组顺序表:只存矩阵的行列维数和三元组顺序表:只存矩阵的行列维数和每个非零元的行列下标及其值每个非零元的行列下标及其值7600070015000001800000240001400003000000000009120MMM由由( (1 1, ,2 2,12), (,
54、12), (1 1, ,3 3,9), (,9), (3 3, ,1 1,-3), (,-3), (3 3, ,6 6,14), (,14), (4 4, ,3 3,24), ,24), ( (5 5, ,2 2,18), (,18), (6 6, ,1 1,15), (,15), (6 6, ,4 4,-7) ,-7) , ,矩阵维数(矩阵维数(6,76,7)和非零元个数和非零元个数唯一确定唯一确定 #define MAXSIZE 12500 typedef struct int i, j; /该非零元的行下标和列下标 ElemType e; / 该非零元的值 Triple; / 三元组类型
55、三元组类型一、一、三元组顺序表三元组顺序表矩阵的顺序存储结构矩阵的顺序存储结构typedef struct Triple dataMAXSIZE + 1; int mu, nu, tu; /矩阵的行数,列数和非零元个数矩阵的行数,列数和非零元个数 TSMatrix; / 稀疏矩阵类型稀疏矩阵类型1 2 121 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 mai j e0 1 2 3 4 5 6 7行列下标行列下标非零元值非零元值7600070015000001800000240001400003000000000009120M以行序为主序:mu=
56、6Nu=7Tu =8如何求转置矩阵?如何求转置矩阵?028003600070500140005280000007143600如果用常规的二维数组表示,则算法为: 其时间复杂度为其时间复杂度为: O(munu) for (col=1; col=nu; +col) for (row=1; row=mu; +row) Tcolrow = Mrowcol;用“三元组”表示如何实现?1 2 141 5 -52 2 -73 1 363 4 282 1 145 1 -52 2 -71 3 364 3 281. 将矩阵的行列值相互交将矩阵的行列值相互交换换2. 2. 将每个元组中的将每个元组中的i i和和j
57、j的值相互调换的值相互调换3. 3. 重排三元组之间的次序重排三元组之间的次序7600070015000001800000240001400003000000000009120M6700000000014000000007000000024009018000121500300N6 7 8 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 i j v 0 1 2 3 4 5 6 7 8mai j v7 6 8 1 3 -3 1 6 15 2 1 12 2 5 18 3 1 9 3 4 24 4 6 -7 6 3 14 0 1 2 3 4
58、 5 6 7 8mb?可用0号单元存储矩阵的行列数和非零元个数方法一:按方法一:按MM的的列序列序转置转置即按即按mbmb中三元组次序依次在中三元组次序依次在mama中找到相中找到相应的三元组进行转置。应的三元组进行转置。为找到为找到MM中每一列所有非零元素,需对其中每一列所有非零元素,需对其三元组表三元组表mama从第一行起扫描一遍。从第一行起扫描一遍。6 7 8 1 2 12 1 3 9 3 1 -3 3 6 14 4 3 24 5 2 18 6 1 15 6 4 -7 i j v0 1 2 3 4 5 6 7 8ma7 6 8 1 3 -3 1 6 15 2 1 12 2 5 18 3
59、1 9 3 4 24 4 6 -7 6 3 14 i j v0 1 2 3 4 5 6 7 8mbkppppppppkkkkppppppppcol=1col=2Status TransposeMatrix(TSMatrix M, TSMatrix &T) /采用三元组表存储表示,求稀疏矩阵采用三元组表存储表示,求稀疏矩阵MM的转置矩阵的转置矩阵T TT.mu=M.mu; T.nu=M.nu; T.tu=M.tu;if(T.tu) q=1;for(col=1;col=M.nu;col+) for(p=1;p=M.tu; +p) if(M.datap.j=col) T.dataq.i=M.data
60、p.j; T.dataq.j=M.datap.i; T.dataq.e=M.datap.e; +q; return Success; /TransposeMatrix算法分析:算法分析:T(n)=O(MT(n)=O(M的列数的列数n n 非零元个数非零元个数t) t)。若若 t t 与与m m n n同数量级,则同数量级,则T(n)=O(mT(n)=O(m* *n n2 2) )方法二:快速转置方法二:快速转置即按即按mama中三元组次序转置,转置结果放入中三元组次序转置,转置结果放入mbmb中恰当位置中恰当位置此法关键是要预先确定此法关键是要预先确定矩阵矩阵mama中每一列第一中每一列第一个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025精算师考试资料:合同责任保险合同所形成的负债
- 借款居间服务合同及借款合同
- 商场简装修店面转让合同书二零二五年
- 大学生职业规划大赛《工程力学专业》生涯发展展示
- 2025《我的雇佣合同》
- 2025房产买卖转让合同
- 一年级 学习生活探索
- 2025个体工商户的股权转让合同
- 2025环卫服务合同范本
- 2025购车贷款合同模板
- 心肺复苏完整版本
- 220kV变电站电气设备常规交接试验方案
- 银行比较新颖的沙龙活动
- 九年级道德与法治上册 第二单元 民主与法治 第四课 建设法治中国教案 新人教版
- 北京市2024年中考历史真题试卷(含答案)
- 学习《吴军阅读与写作》 (50讲 )
- 房产证代办服务合同
- 尾矿库基本知识
- 财会实操-体育馆的账务处理分录
- DL∕T 1094-2018 电力变压器用绝缘油选用导则
- 2024山东能源集团中级人才库选拔高频考题难、易错点模拟试题(共500题)附带答案详解
评论
0/150
提交评论