数据结构 3栈和队列

合集下载

数据结构——用C语言描述(第3版)教学课件第3章 栈和队列

数据结构——用C语言描述(第3版)教学课件第3章 栈和队列

if(S->top==-1) /*栈为空*/
return(FALSE);
else
{*x = S->elem[S->top];
return(TRUE);
}
返回主目录}[注意]:在实现GetTop操作时,也可将参数说明SeqStack *S 改为SeqStack S,也就是将传地址改为传值方式。传 值比传地址容易理解,但传地址比传值更节省时间、 空间。
返回主目录
算法:
void BracketMatch(char *str) {Stack S; int i; char ch; InitStack(&S); For(i=0; str[i]!='\0'; i++) {switch(str[i])
{case '(': case '[': case '{':
3.1.3 栈的应用举例
1. 括号匹配问题
思想:在检验算法中设置一个栈,若读入的是左括号, 则直接入栈,等待相匹配的同类右括号;若读入的是 右括号,且与当前栈顶的左括号同类型,则二者匹配, 将栈顶的左括号出栈,否则属于不合法的情况。另外, 如果输入序列已读尽,而栈中仍有等待匹配的左括号, 或者读入了一个右括号,而栈中已无等待匹配的左括 号,均属不合法的情况。当输入序列和栈同时变为空 时,说明所有括号完全匹配。
return(TRUE);
}
返回主目录
【思考题】
如果将可利用的空闲结点空间组织成链栈来管理,则申 请一个新结点(类似C语言中的malloc函数)相当于链 栈的什么操作?归还一个无用结点(类似C语言中的 free函数)相当于链栈的什么操作?试分别写出从链栈 中申请一个新结点和归还一个空闲结点的算法。

数据结构(C语言)第3章 栈和队列

数据结构(C语言)第3章 栈和队列

Data Structure
2013-8-6
Page 13
栈的顺序存储(顺序栈)
利用一组地址连续的存储单元依次存放自栈底到栈顶的数 据元素。 结构定义: #define STACK_INIT_SIZE 100; // 存储空间初始分配量 #define STACKINCREMENT 10; // 存储空间分配增量 typedef struct { SElemType *base; // 存储空间基址 SElemType *top; // 栈顶指针 int stacksize; // 当前已分配的存储空间,以元素位单位 } SqStack;
解决方案2:
顺序栈单向延伸——使用一个数组来存储两个栈
Data Structure 2013-8-6 Page 21
两栈共享空间 两栈共享空间:使用一个数组来存储两个栈,让一个 栈的栈底为该数组的始端,另一个栈的栈底为该数组 的末端,两个栈从各自的端点向中间延伸。
Data Structure
2013-8-6
链栈需要加头结点吗? 链栈不需要附设头结点。
Data Structure
2013-8-6
Page 27
栈的链接存储结构及实现
Data Structure
2013-8-6
Page 11
GetTop(S, &e) 初始条件:栈 S 已存在且非空。 操作结果:用 e 返回S的栈顶元素。 Push(&S, e) 初始条件:栈 S 已存在。 操作结果:插入元素 e 为新的栈顶元素。 Pop(&S, &e) 初始条件:栈 S 已存在且非空。 操作结果:删除 S 的栈顶元素,并用 e 返回其值。
Data Structure

数据结构课件第3章

数据结构课件第3章

0
1
2
3
4
5
6
7
a1
a2
a3
a4
a5
a6
a7
队头 F=0
队尾 R=7
a3 2 1 3 0 4 7 a3 5 6 3 a2 2 1 a1 0 F=0 a4 4 a5 5 6 a6 7 a7 R=0 R=7 3 a2 2 1 a1 0
a4 4 a5 5 6 a6 7
a8
F=0
a7
R=0
F=0
删除所有元素
top X W … B top
top=0 空栈
top
W

B A
top=m-1 元素X出栈
top
A
A
top=m 满栈
top=1 元素A入栈
例:堆栈的插入、删除操作。 出栈操作程序如下: # define m 1000; /*最大栈空间*/ 出栈操作算法: 1)栈顶指针top是否为0: typedef struct stack_stru 若是,则返回;若不是, { int s[m]; int top; }; 则执行2。 void pop (stack, y) 2)将栈顶元素送给y, struct stack_stru stack; 栈顶指针减1。 int *y; { if (stack.top = = 0) printf (“The stack is empty ! \n”); top Y Y else { top B B *y=stack.s[stack.top]; A A stack.top - -; } 出栈操作 }
top=p;
} 栈的入栈、出栈操作的时间复杂度都为O(1)。
栈的应用
一、 表达式求值 表达式由操作数、运算符和界限符组成。 运算符可包括算术运算符、关系运算符、逻辑运算符。

大学数据结构课件--第3章 栈和队列

大学数据结构课件--第3章 栈和队列
top top 栈空 F E D C B A
栈满 top-base=stacksize
top
F
E
D C B
top top top top top top base
入栈PUSH(s,x):s[top++]=x; top 出栈 POP(s,x):x=s[--top]; top
base
4
A
3.1 栈
例1:一个栈的输入序列为1,2,3,若在入栈的过程中 允许出栈,则可能得到的出栈序列是什么? 答: 可以通过穷举所有可能性来求解:
3.2 栈的应用举例
二、表达式求值
“算符优先法”
一个表达式由操作数、运算符和界限符组成。 # 例如:3*(7-2*3) (1)要正确求值,首先了解算术四则运算的规则 a.从左算到右 b.先乘除后加减 c.先括号内,后括号外 所以,3*(7-2*3)=3*(7-6)=3*1=3
9
3.2 栈的应用举例
InitStack(S); while (!QueueEmpty(Q))
{DeQueue(Q,d);push(S,d);}
while (!StackEmpty(S)) {pop(S,d);EnQueue(Q,d);} }
第3章 栈和队列
教学要求:
1、掌握栈和队列的定义、特性,并能正确应用它们解决实 际问题;
用一组地址连续的存储单元依次存放从队头到队尾的元素, 设指针front和rear分别指示队头元素和队尾元素的位置。
Q.rear 5 4 Q.rear 3 2 3 2 5 4 Q.rear 3 3 5 4 5 4
F E D C
C B A
Q.front
2 1 0
C B
Q.front 2 1 0

国家开放大学《数据结构》课程实验报告(实验3 ——栈、队列、递归设计)参考答案

国家开放大学《数据结构》课程实验报告(实验3 ——栈、队列、递归设计)参考答案
{
x=Pop(s); /*出栈*/
printf("%d ",x);
InQueue(sq,x); /*入队*/
}
printf("\n");
printf("(10)栈为%s,",(StackEmpty(s)?"空":"非空"));
printf("队列为%s\n",(QueueEmpty(sq)?"空":"非空"));
ElemType Pop(SeqStack *s); /*出栈*/
ElemType GetTop(SeqStack *s); /*取栈顶元素*/
void DispStack(SeqStack *s); /*依次输出从栈顶到栈底的元素*/
void DispBottom(SeqStack *s); /*输出栈底元素*/
} SeqQueue; /*定义顺序队列*/
void InitStack(SeqStack *s); /*初始化栈*/
int StackEmpty(SeqStack *s); /*判栈空*/
int StackFull(SeqStack *s); /*判栈满*/
void Push(SeqStack *s,ElemType x); /*进栈*/
sq=(SeqQueue *)malloc(sizeof(SeqQueue));
InitQueue(sq);
printf("(8)队列为%s\n",(QueueEmpty(sq)?"空":"非空"));
printf("(9)出栈/入队的元素依次为:");

数据结构相关题库及答案

数据结构相关题库及答案

数据结构相关题库及答案第三章栈和队列一、判断题:1、栈和队列都是限制存取点的线性结构(易)2、栈和队列是两种重要的线性结构。

(易)3、带头结点的单链表形式的队列,头指针F指向队列的头结点,尾指针R指向队列的最后一个结点(易)4、在对不带头结点的链队列作出队操作时,不会改变头指针的值。

(易)答案:1-4 √√××二、选择题:1、一个栈的入栈序列a,b,c,d,e,则栈的不可能的输出序列是C____。

A、 edcba B、 decbaC、 dceabD、 abcde2、若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pn,若p1=n,则pi为_C___。

A、 iB、 n=iC、 n-i+1D、不确定3、栈结构通常采用的两种存储结构是_A___。

A、顺序存储结构和链式存储结构B、散列方式和索引方式C、链表存储结构和数组D、线性存储结构和非线性存储结构4、判定一个顺序栈ST(最多元素为m0)为空的条件是_B___。

A、top !=0B、top= =0C、top !=m0D、top= =m0-15、判定一个顺序栈ST(最多元素为m0)为栈满的条件是D。

A、top!=0 B、top= =0 C、top!=m0 D、top= =m0-16、队列操作的原则是( A ) A、先进先出 B、后进先出 C、只能进行插入 D、只能进行删除7、向一个栈顶指针为HS的链栈中插入一个s所指结点时,则执行__ _C_。

(不带空的头结点) (易)A、HS—>next=s;9B、s—>next= HS—>next; HS—>next=s;C、s—>next= HS; HS=s;D、s—>next= HS; HS= HS—>next8、从一个栈顶指针为HS的链栈中删除一个结点时,用x保存被删结点的值,则执行__ _B_。

(不带空的头结点) (中)A、x=HS; HS= HS—>next;B、x=HS—>data;C、HS= HS—>next; x=HS—>data;D、x=HS—>data; HS= HS—>next;9、一个队列的数据入列序列是1,2,3,4,则队列的出队时输出序列是___C_ 。

数据结构栈和队列ppt课件


栈的运用 例3.1 将一个十进制正整数N转换成r进制的数
N 〕
1835
229
28
3
N / 8 〔整除〕 N % 8〔求余
229
3

28
5
3
4
0
3

❖例3.2 算术表达式中括号匹配的检查
❖用栈来实现括号匹配检查的原那么是,对表达式从左 到右扫描。
❖〔1〕当遇到左括号时,左括号入栈;
❖〔2〕当遇到右括号时,首先检查栈能否空,假设栈 空,那么阐明该“右括弧〞多余;否那么比较栈顶左 括号能否与当前右括号匹配,假设匹配,将栈顶左括 号出栈,继续操作;否那么,阐明不匹配,停顿操作 。
❖在顺序栈上实现五种根本运算的C函数 ❖〔3〕入栈 ❖int push (SeqStack *s, DataType x) ❖{ if (s->top==MAXSIZE-1) /*栈满不能入栈*/ ❖{ printf("overflow"); ❖return 0; ❖} ❖ s->top++; ❖ s->data[s->top]=x; ❖ return 1; ❖}
链队列及运算的实现
采用链接方法存储的队列称为链队列〔Linked Queue〕
采用带头结点的单链表来实现链队列,链队列中 的t结ype点de类f st型ruc与t N单od链e 表一样。将头指针front和尾指针 re{arD封at装aTy在pe一da个ta;构造体中,链队列用C言语描画如 下:struct Node *next;
❖只设了一个尾指针r ❖头结点的指针,即r->next ❖队头元素的指针为r->next->next ❖队空的断定条件是r->next==r

《数据结构(C语言)》第3章 栈和队列

Data structures

❖ 栈的顺序存储与操作 ❖ 1.顺序栈的定义
(1) 栈的静态分配顺序存储结构描述 ② top为整数且指向栈顶元素 当top为整数且指向栈顶元素时,栈空、入栈、栈满 及出栈的情况如图3.2所示。初始化条件为 S.top=-1。
(a) 栈空S.top==-1 (b) 元素入栈S.stack[++S.top]=e (c) 栈满S.top>=StackSize-1 (d) 元素出栈e=S.stack[S.top--]
/*栈顶指针,可以指向栈顶
元素的下一个位置或者指向栈顶元素*/
int StackSize; /*当前分配的栈可使用的以 元素为单位的最大存储容量*/
}SqStack;
/*顺序栈*/
Data structures

❖ 栈的顺序存储与操作 ❖ 1.顺序栈的定义
(2) 栈的动态分配顺序存储结构描述 ① top为指针且指向栈顶元素的下一个位置 当top为指针且指向栈顶元素的下一个位置时,栈空 、入栈、栈满及出栈的情况如图3.3所示。初始化条 件为S.top=S.base。
…,n-1,n≥0} 数据关系:R={< ai-1,ai>| ai-1,ai∈D,i=1,2
,…,n-1 } 约定an-1端为栈顶,a0端为栈底 基本操作:
(1) 初始化操作:InitStack(&S) 需要条件:栈S没有被创建过 操作结果:构建一个空的栈S (2) 销毁栈:DestroyStack(&S) 需要条件:栈S已经被创建 操作结果:清空栈S的所有值,释放栈S占用的内存空间
return 1;
}
Data structures

栈和队列先进先出和后进先出的数据结构

栈和队列先进先出和后进先出的数据结构栈和队列是常用的数据结构,它们分别以先进先出(FIFO)和后进先出(LIFO)的方式来组织和管理数据。

在许多编程语言中,栈和队列被广泛应用于解决各种问题。

本文将从定义、特点、应用和实现这几个方面来介绍栈和队列。

一、定义栈(Stack)是一种只允许在固定一端进行插入和删除操作的线性数据结构。

这一端被称为栈顶,而另一端被称为栈底。

栈的特点是先进后出。

队列(Queue)是一种先进先出的线性数据结构,允许在一端进行插入操作,而在另一端进行删除操作。

插入操作在队列的尾部进行,删除操作则在队列的头部进行。

二、特点2.1 栈的特点(1)插入和删除操作只能在栈顶进行,保证数据的顺序。

(2)栈是一种后进先出(LIFO)的数据结构,也就是最后插入的元素最先被删除。

(3)栈只能在栈顶进行插入和删除操作,不允许在中间或者底部进行操作。

2.2 队列的特点(1)插入操作只能在队列的尾部进行,保证数据的顺序。

(2)删除操作只能在队列的头部进行,始终删除最先插入的元素。

(3)队列是一种先进先出(FIFO)的数据结构,也就是最先插入的元素最早被删除。

三、应用3.1 栈的应用(1)函数调用和递归:栈被用于保存函数调用时的局部变量和返回地址。

(2)表达式求值:使用栈来实现中缀表达式转换为后缀表达式,然后计算结果。

(3)括号匹配:通过栈检查括号是否配对合法。

(4)浏览器的前进和后退:把浏览器的访问记录保存在栈中,方便前进和后退操作。

3.2 队列的应用(1)任务调度:使用队列管理任务,在现有任务执行完毕后按照先后顺序执行新任务。

(2)缓存管理:常用的缓存淘汰策略是先进先出,即最早进入缓存的数据最早被淘汰。

(3)消息队列:实现进程间的异步通信,提高系统的并发性和可扩展性。

(4)打印队列:打印任务按照先后顺序排队执行,保证打印的顺序。

四、实现栈和队列可以通过数组或链表来实现。

使用数组实现的栈和队列称为顺序栈和顺序队列,而使用链表实现的栈和队列称为链式栈和链式队列。

数据结构第3章栈

Elemtype pop(sqstack *s) { /*若栈s不为空,则删除栈顶元素*/ Elemtype x; if(s->top<0) return NULL; /*栈空*/ x=s->stack[s->top]; s->top--; return x; }
13
(4)取栈顶元素操作
Elemtype gettop(sqstack *s) { /*若栈s不为空,则返回栈顶元素*/ If(s->top<0) return NULL; /*栈空*/ return (s->stack[s->top]); }

29
算术表达式求值
在计算机中,任何一个表达式都是由: 操作数(operand)、运算符(operator)和 界限符(delimiter)组成的。 其中操作数可以是常数,也可以是变量或常量的 标识符;运算符可以是算术运算体符、关系运算符和 逻辑符;界限符为左右括号和标识表达式结束的结束 符。
30
6
存储结构
栈是一种特殊的线性表,有两种存储方式: 顺序存储结构存储
链式存储结构存储。


7
顺序栈的数组表示
与第二章讨论的一般的顺序存储结构的线性表 一样,利用一组地址连续的存储单元依次存放自 栈底到栈顶的数据元素,这种形式的栈也称为顺 序栈。 使用一维数组来作为栈的顺序存储空间。 设指针top指向栈顶元素的当前位置,以数组 小下标的一端作为栈底。 top=0时为空栈,元素进栈时指针top不断地 加1,当top等于数组的最大下标值时则栈满。
5)假如读出的运算符的优先级不大于运算符栈栈顶运算符
的优先级,则从操作数栈连续退出两个操作数,从运算符栈中 退出一个运算符,然后作相应的运算,并将运算结果压入操作 数栈。此时读出的运算符下次重新考虑(即不读入下一个符号 )。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第3章 栈和队列
4. 顺序栈的输出
将顺序栈中当前的元素值输出(从栈顶开始输出) ➊ 程序实现
/*=================================== 函数功能:顺序栈输出 函数输入:顺序栈地址 函数输出:无 ====================================*/ void PrintStack(SeqStack *s) { int i; if(Empty_SeqStack(s)==1) //栈空不输出 { printf("顺序栈为空\n"); exit(1); } else for(i=s->top;i>=0;i--) printf("%4d",s->data[i]); }
第3章 栈和队列
顺序栈和链栈的比较
时间效率
空间效率
顺序栈
链式栈 说明
所有操作都只需常数时间
链式栈在栈顶操作,效率很高
顺序栈须长度固定
链式栈的长度可扩展,但增加结构性 开销
顺序栈和链式栈在时间效率上难 实际应用中,顺序栈比链式栈用得更 分伯仲 广泛些
顺序栈的缺点是栈满后不 能再进栈,链栈无栈满问 题(系统资源足够时)。
第3章 栈和队列
/*================================= 函数功能:链栈的进栈操作 函数输入:(栈顶指针)、进栈元素 函数输出:栈顶指针 =================================*/ LinkStack Push_LinkStack(LinkStack top, ElemType x ) { LinkStack p; p=(LinkStack)malloc( sizeof(StackNode) ); p->data=x; p->next=top; top= p; return top; }
第3章 栈和队列
3. 顺序栈的入栈
将值为x的元素放入栈中。 ➊ 算法分析 进栈前,栈顶指针top指向an,要将x入栈:
(1)先将top加1,指向an的上一个位置;
(2)再把x放入top所指向的位置。 注意:栈满时,不能入栈,否则出现空间溢出——上溢。
第3章 栈和队列
第3章 栈和队列
❷ 函数结构设计
栈(Stack)是一种特殊的线性表,它所有的插入和删除
都限制在表的同一端进行。
第3章 栈和队列 (1)栈中允许进行插入、删除操作的一端叫做栈顶(Top),另一 端叫做栈底(Bottom)。 (2)当栈中没有元素时,称之为空栈。 (3)栈的插入操作——进栈(入栈、压栈)Push (4)栈的删除操作——出栈(弹栈)Pop
3.2 栈的顺序存储结构
第3章 栈和队列
栈是一种特殊的线性表,其存储结构可采用线性表 的存储形式——顺序结构和链式结构。
逻辑关系 线性
特殊
存储结构 采用线性表的各种方案

线性表
运算 限定在线性表一端
第3章 栈和队列
3.2.1 顺序栈的定义及其数据结构
1. 顺序栈
顺序表
用一块连续空间顺 序存放栈元素
出栈元素值 ElemType *
函数名
形参
函数类型
第3章 栈和队列 ❹ 算法描述
顶部伪代码描述
第一步细化 若栈空,则return 0;
删除栈顶数据元素
记录栈顶元素值x 修改栈顶指针:top-return 1
第3章 栈和队列 ❺ 程序实现
/*============================= 函数功能:顺序栈出栈操作 函数输入:顺序栈地址,出栈元素地址 函数输出:0——栈下溢,操作失败;1——操作正常 ===============================*/ int Pop_SeqStack(SeqStack* s, ElemType* x) { if (Empty_SeqStack(s)==1) return 0; //栈空,不能出栈 else { *x= s->data[s->top]; //栈顶元素放入变量x s->top--; } return 1; }
第3章 栈和队列
2. 顺序栈的判空
判断栈空,查看栈中是否有元素。 ❶ 函数结构设计
功能描述
判栈空 Empty_SeqStack 函数名
输入
顺序栈地址 Seqstack * 形参
输出
栈状态标志 int (栈空:1;非空:0) 函数类型
第3章 栈和队列 ❷ 程序实现
/*================================ 函数功能:判断顺序栈是否为空 函数输入:顺序栈地址 函数输出:1——栈空;0——栈非空 =================================*/ int Empty_SeqStack(SeqStack* s) { if(s->top == -1 ) return 1; //栈空 else return 0; //栈非空 }
第3章 栈和队列 栈空:top=-1 栈满:top=MAXSIZE-1
MAXSIZE-1 … n
n-1
n-2 … 1 0
an
an-1 … a2 a1
top
顺序栈示意图
第3章 栈和队列
3.2.2 顺序栈的运算
1. 顺序栈的初始化(置空栈)
对栈初始化,将栈顶指针置为-1。 ❶ 函数结构设计
功能描述 栈初始化 输入 顺序栈地址 输出
第3章 栈和队列
2. 出栈
在链栈栈顶位置删除结点
仍然要判 断栈空
第3章 栈和队列
/*===================================== 函数功能:链栈的出栈操作 函数输入:栈顶指针、(出栈元素) 函数输出:栈顶指针 =====================================*/ LinkStack Pop_LinkStack(LinkStack top, ElemType* x) { LinkStack p; if(top==NULL) return NULL; else //链栈不为空 { *x=top->data; p=top; top=top->next; free(p); return top; } }
//数据域 //指针域
第3章 栈和队列 链栈是运算受限的单链表,其插入和删除操作仅限制在表 头位置上进行。 在单链表的头部作为栈顶,不需要带头结点的单链表。
空栈:top=NULL
栈顶指针就是 链表的头指针
栈满:基本不会
第3章 栈和队列
3.3.2 链栈的运算
1. 进栈
在链栈栈顶位置插入值为x的新结点
第三章 栈和队列
3.1 栈的定义及基本运算
目 录
3.2 栈的顺序存储结构
3.3 栈的链式存储结构
3.4 队列的定义及基本运算
3.5 队列的顺序存储结构
3.6 队列的链式存储结构
第3章 栈和队列
栈和队列是两种特殊的线性结构,也是两种重要的线性结
构。
从数据的逻辑结构角度来看,栈和队列是线性表; 从操作的角度来看,栈和队列的操作是受限的线性表。 栈和队列在计算机操作系统、程序编译系统和应用软件系 统中得到了广泛应用。例如,程序编译系统中应用栈检查语法、
计算表达式的值、调用函数和实现递归等;计算机操作系统的
作业管理中要用到队列。
3.1 栈的定义及基本运算
第3章 栈和队列
3.1.1 栈的定义
1. 栈的实际例子
WORD的撤销操作
3 2 1
后进的先出
第3章 栈和队列

2. 栈的定义
数据处理过程的特点:
后进先出(Last In First Out, LIFO)
输入 栈顶指针 > 0 栈顶指针 = 0 栈顶指针=-1
预期结果 返回栈顶元素值 返回出栈操作正常标志 返回出栈操作异常标志
第3章 栈和队列 ❸ 函数结构设计
功能描述
出栈 Pop_SeqStack
输入
顺序栈地址SeqStack * (出栈元素值 ElemType*)
输出
操作状态 int (正常:1;下溢:0)
第3章 栈和队列
6. 顺序栈取栈顶元素
取栈顶元素的值,而不改变栈顶指针top。
➊ 程序实现
/*================================= 函数功能:顺序栈取栈顶元素 函数输入:顺序栈地址,(栈元素地址) 函数输出:0——栈下溢,操作失败;1——操作正常 ===================================*/ int Gettop_SeqStack(SeqStack* s, ElemType* x) { if ( Empty_SeqStack(s)==1) return 0; //栈空 else { *x= s->data[s->top]; } return 1; }
Init_SqStack
函数名
SeqStack *
形参

函数类型
第3章 栈和队列 ❷ 程序实现
/*================================= 函数功能:顺序栈置空栈 函数输入:顺序栈地址 函数输出:无 ===================================*/ void Init_SeqStack( SeqStack* s ) { s->top = -1; }
第3章 栈和队列
5. 顺序栈的出栈
删除栈顶数据元素
➊ 算法分析 出栈时,栈顶指针top指向an,要将an出栈: (1)先获得an的元素值; (2)再top减1。 注意:注意:栈空时,不能出栈。
第3章 栈和队列
第3章 栈和队列 ❷ 测试用例
相关文档
最新文档