1.第三章学习了两种特殊的线性表----栈和队列。栈亦称为后进先出的线性表,LIFO,包括顺序栈和链栈;队列亦称为先进先出的线性表,FIFO,包括循环队列和链队。顺序栈和循环队列的定义和基本操作与第二章所学的顺序表有相似之处,链栈和链队与链表亦是如此。
一、栈
1 //顺序栈--栈顶进出 2 const int MAXSIZE=100; 3 typedef int SElemType; 4 typedef struct 5 { 6 SElemType data[MAXSIZE]; 7 int top; //栈顶标志 8 int stacksize; //栈的最大容量 9 }SqStack; 10 11 void InitStack(SqStack &S) 12 { 13 S.top=0; 14 S.stacksize=MAXSIZE; 15 } 16 17 bool StackFull(SqStack &S) 18 { 19 if(S.top==S.stacksize) return true; 20 else return false; 21 } 22 23 bool StackEmpty(SqStack &S) 24 { 25 if(S.top==0) return true; 26 else return false; 27 } 28 29 void Push(SqStack &S, SElemType e) //栈顶入栈 30 {//需先判断栈是否满 31 S.data[S.top]=e; 32 S.top++; 33 } 34 35 void Pop(SqStack &S, SElemType &e) //栈顶出栈 36 {//需先判断栈是否空 37 S.top--; 38 e=S.data[S.top]; 39 } 40 41 //链栈--栈顶进出,无需设置头结点 42 typedef struct StackNode 43 { 44 SElemType data; 45 struct StackNode *next; 46 }StackNode, *LinkStack; 47 48 void InitStack(LinkStack &S) 49 { 50 S=NULL; 51 } 52 53 bool StackEmpty(LinkStack S) 54 { 55 if(S=NULL) return true; 56 else return false; 57 } 58 59 Status Push(LinkStack &S, SElemType e) //栈顶入栈 60 { 61 StackNode *p=new StackNode; 62 if(p==NULL) exit(OVERFLOW); 63 p->data=e; 64 p->next=S; 65 S=p; 66 return OK; 67 } 68 69 void Pop(LinkStack &S, SElemType &e) //栈顶出栈 70 {//需先判断栈是否空 71 StackNode *p; 72 e=S->data; 73 p=S; 74 S=S->next; 75 delete p; 76 }
注:递归与栈联系紧密,在计算机系统中,使用栈来实现递归。
二、队列
1 //循环队列--尾进头出 2 const int MAXQSIZE=100; 3 typedef int QElemType; 4 typedef struct 5 { 6 QElemType data[MAXQSIZE]; 7 int front; //头指针 8 int rear; //尾指针 9 }SqQueue; 10 11 void InitQueue(SqQueue &Q) 12 { 13 Q.front=Q.rear=0; 14 } 15 16 int QueueLength(SqQueue Q) 17 { 18 return (Q.rear-Q.front+MAXQSIZE) % MAXQSIZE; //模运算 19 } 20 21 bool QueueFull(SqQueue Q) 22 { 23 if((Q.rear+1) % MASQSIZE==Q.front) //模运算 24 return true; 25 else return false; 26 } 27 28 bool QueueEmpty(SqQueue Q) 29 { 30 if(Q.front==Q.rear) 31 return true; 32 else return false; 33 } 34 35 void EnQueue(SqQueue &Q, QElemType e)//队尾入队 36 {//需先判断队是否满 37 Q.data[Q.rear]=e; 38 Q.rear=(Q.rear+1) % MAXQSIZE; //模运算 39 } 40 41 void DeQueue(SqQueue &Q, QElemType &e)//队头出队 42 { 43 e=Q.tata[Q.front]; 44 Q.front=(Q.front+1) % MAXQSIZE; //模运算 45 } 46 47 //链队--尾进头出,设有头结点 48 typedef struct QNode 49 { 50 QElemType data; 51 struct QNode *next; 52 }QNode, *QueuePtr; 53 typedef struct 54 { 55 QueuePtr front; //队头指针,始终指向头结点(无数据) 56 QueuePtr rear; //队尾指针,始终指向最后一个结点 57 }LinkQueue; 58 59 Status InitQueue(LinkQueue &Q) 60 { 61 Q.front=new QNode; 62 if(Q.front==NULL) exit(OVERFLOW); 63 Q.front->next=NULL; 64 Q.rear=Q.front; 65 return OK; 66 } 67 68 bool QueueEmpty(LinkQueue Q) 69 { 70 if(Q.front==Q.rear) return true; 71 else return false; 72 } 73 74 Status EnQueue(LinkQueue &Q, QElemType e) 75 { 76 QNode *p; 77 p=new QNode; 78 if(p==NULL) exit(OVERFLOW); 79 p->data=e; 80 p->next=NULL; 81 Q.rear->next=p; 82 Q.rear=p; 83 return OK; 84 } 85 86 void DeQueue(LinkQueue &Q, QElemType &e) 87 {//需先判断队是否空 88 QNode *p; 89 p=Q.front->next; 90 e=p->data; 91 Q.front->next=p->next; 92 if(Q.rear==p) //最后一个结点出队 93 Q.front=Q.rear; 94 delete p; 95 }
注:队列中的链队涉及到模运算,不是简单的加减1而已。
我认为栈和队列的应用应该根据具体情况分析,数据的输入和输出、存储方式和处理方式共同影响着使用的线性表类型。由课本的案例,数制的转换、括号匹配的检验、表达式求值和舞伴问题,都展现了这一点。学好这两种线性表的定义和基本操作是基础,关键是对问题要有清楚的分析和清晰的逻辑思维。
2.做作业的判断题和单选题都是在看完课本才去做,编程题一般先自己看完,想想思路(一般想不出来),然后就看“带你打代码”,在完全理解逻辑之后再去pta复现的。做实践题之前,我总会先去看题目,然后先思索要使用什么类型的线性表来处理这个问题。有时候一直卡在一个点的时候,就去翻翻书,看看以前的问题,总能有不同的收获。有时实在想不出来,也会问问同学,虽然我们使用的线性表类型不同,但总会有不同的收获。这一次小组协作,我们可能一开始就在大方向上出现错误,一直想要使用顺序表来解决问题,但出现运行超市的问题,便考虑使用二分法,虽然还是没能解决这个问题,但最后使用链表终于完成了题目。
3.我觉得在现有能力下,书本是我最好的学习资料。无论多忙,一定要空出时间提前预习课本内容,到上课时一定会有意想不到的收获。
4.经过第三章的学习,感觉似乎对第二章的内容又复习了一遍。渐渐能完全理解这些定义和基本操作了。接下来还是要多打代码,用多种方式做pta的题,和同学相互借鉴。