栈 stack 栈是限定仅在表尾进行插入和删除操作的线性表 。把允许插入和删除的一端称为栈顶(top) ,另一端称为栈底(bottom) ,不含任何数据元素的栈称为空栈。栈又称为后进先出(Last In First Out)的线性表,简称 LIFO 结构。
栈的顺序存储结构实现 因为栈本身属于线性表的特例,那么栈的顺序存储其实也是线性表顺序存储的简化,称为顺序栈。
sqstack.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #ifndef SQSTACK_H #define SQSTACK_H #define OK 1 #define ERR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 5 typedef int Elemtype;typedef int Status;typedef struct { Elemtype data[MAXSIZE]; int top; }Sqstack; Status InitStack (Sqstack *S) ;Status ClearStack (Sqstack *S) ;Status StackEmpty (Sqstack S) ;int StackLength (Sqstack S) ;Status GetTop (Sqstack S,Elemtype *e) ;Status Push (Sqstack *S,Elemtype e) ;Status Pop (Sqstack *S,Elemtype *e) ;Status visit (Elemtype c) ;Status StackTraverse (Sqstack S) ;#endif
sqstack.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 #include "stdio.h" #include "sqstack.h" Status InitStack (Sqstack *S) { S->top = -1 ; return OK; } Status ClearStack (Sqstack *S) { S->top = -1 ; return OK; } Status StackEmpty (Sqstack S) { if (S.top==-1 ) return TRUE; else return FALSE; } int StackLength (Sqstack S) { return S.top+1 ; } Status GetTop (Sqstack S,Elemtype *e) { if (S.top==-1 ) return ERR; else *e=S.data[S.top]; return OK; } Status Push (Sqstack *S,Elemtype e) { if ( S->top == MAXSIZE-1 ) { printf ("栈满!" ); return ERR; } S->top++; S->data[S->top]=e; return OK; } Status Pop (Sqstack *S,Elemtype *e) { if (S->top == -1 ) { printf ("栈空!" ); return ERR; } *e=S->data[S->top]; S->top--; return OK; } Status visit (Elemtype c) { printf ("%d " ,c); return OK; } Status StackTraverse (Sqstack S) { int i; i=0 ; while (i<=S.top) { visit(S.data[i++]); } printf ("\n" ); return OK; } int main (int argc, char *argv[]) { int opt; int exit = OK; Sqstack test; InitStack(&test); while (exit ) { printf ("\n======================================================================================================================== \n" ); printf (">>>请输入操作标号: 1.初始化栈; 2.将元素e入栈; 3.将栈顶元素弹出; 4.将栈清空; 5.打印栈内元素; 0.退出;\n" ); scanf ("%d" ,&opt); switch (opt) { case 1 : { InitStack(&test); printf ("初始化完成,目前栈为空!\n" ); } break ; case 2 : { Elemtype val; printf ("请输入入栈元素的值并按回车:\n" ); scanf ("%d" ,&val); if (Push(&test,val)) { printf ("入栈成功!目前栈内有%d个元素。\n" ,StackLength(test)); } } break ; case 3 : { Elemtype val; if (Pop(&test,&val)) { printf ("栈顶元素%d弹出,目前栈内有%d个元素。\n" ,val,StackLength(test)); } } break ; case 4 : { if (ClearStack(&test)) printf ("清空完成,目前栈内有%d个元素。\n" ,StackLength(test)); } break ; case 5 : { printf ("目前栈内有%d个元素,分别是:\n" ,StackLength(test)); StackTraverse(test); } break ; case 0 : exit = ERR; printf ("Goodbye~\n" ); break ; default : printf ("输入错误请按标号重新输入!\n" ); } } return 0 ; }
栈的链式存储结构实现 LinkStack.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #ifndef LINKSTACK_H #define LINKSTACK_H #define OK 1 #define ERR 0 #define TRUE 1 #define FALSE 0 typedef int Elemtype;typedef int Status;typedef struct StackNode { Elemtype data; struct StackNode *next ; }StackNode,*LinkStackPtr; typedef struct { LinkStackPtr top; int count; }LinkStack; Status visit (Elemtype c) ;Status InitStack (LinkStack *S) ;Status StackEmpty (LinkStack S) ;Status ClearStack (LinkStack *S) ;int StackLength (LinkStack S) ;Status GetTop (LinkStack S,Elemtype *e) ;Status Push ( LinkStack *S,Elemtype e ) ;Status Pop ( LinkStack *S,Elemtype *e ) ;Status StackTraverse (LinkStack S) ;#endif
LinkStack.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 #include "stdio.h" #include "stdlib.h" #include "LinkStack.h" Status InitStack (LinkStack *S) { S->top = NULL ; S->count=0 ; return OK; } Status StackEmpty (LinkStack S) { if (S.count==0 ) return TRUE; else return FALSE; } Status ClearStack (LinkStack *S) { LinkStackPtr pxTop,temp; pxTop = S->top; while (pxTop) { temp=pxTop; pxTop=pxTop->next; free (temp); } S->count=0 ; return OK; } int StackLength (LinkStack S) { return S.count; } Status GetTop (LinkStack S,Elemtype *e) { if (S.top==NULL ) return ERR; else *e=S.top->data; return OK; } Status Push ( LinkStack *S,Elemtype e ) { LinkStackPtr newnode = (LinkStackPtr)malloc (sizeof (StackNode)); newnode->data = e; newnode->next = S->top; S->top = newnode; S->count++; return OK; } Status Pop ( LinkStack *S,Elemtype *e ) { LinkStackPtr pxTop; if (StackEmpty(*S)) return ERR; pxTop = S->top; *e = pxTop->data; S->top = S->top->next; free (pxTop); S->count--; return OK; } Status visit (Elemtype c) { printf ("%d " ,c); return OK; } Status StackTraverse (LinkStack S) { if (S.count == 0 ) { printf ("栈空!\n" ); return ERR; } LinkStackPtr p=S.top; while (p) { visit(p->data); p=p->next; } printf ("\n" ); return OK; } int main (int argc, char *argv[]) {int opt; int exit = OK; LinkStack test; InitStack(&test); while (exit ) { printf ("\n======================================================================================================================== \n" ); printf (">>>请输入操作标号: 1.初始化栈; 2.将元素e入栈; 3.将栈顶元素弹出; 4.将栈清空; 5.打印栈内元素; 0.退出;\n" ); scanf ("%d" ,&opt); switch (opt) { case 1 : { InitStack(&test); printf ("初始化完成,目前栈为空!\n" ); } break ; case 2 : { Elemtype val; printf ("请输入入栈元素的值并按回车:\n" ); scanf ("%d" ,&val); if (Push(&test,val)) { printf ("入栈成功!目前栈内有%d个元素。\n" ,StackLength(test)); } } break ; case 3 : { Elemtype val; if (Pop(&test,&val)) { printf ("栈顶元素%d弹出,目前栈内有%d个元素。\n" ,val,StackLength(test)); } } break ; case 4 : { if (ClearStack(&test)) printf ("清空完成,目前栈内有%d个元素。\n" ,StackLength(test)); } break ; case 5 : { printf ("目前栈内有%d个元素,分别是:\n" ,StackLength(test)); StackTraverse(test); } break ; case 0 : exit = ERR; printf ("Goodbye~\n" ); break ; default : printf ("输入错误请按标号重新输入!\n" ); } } return 0 ; }
栈总结 由于链栈每个元素都有指针域增加了一些内存开销,所以在栈的大小相对确定或变化在可控范围内时最好使用顺序栈。反之如果栈中的元素变化不可预料,最好使用对于栈长度无限制的链栈。
队列 queue 队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。把允许插入的一端称为队尾,允许删除的一端称为队头。队列又称为先进先出(First In First Out)的线性表,简称 FIFO 结构。
队列也是作为一种特殊的线性表,同样存在顺序存储、链式存储两种存储方式。
队列的顺序存储 sqqueue.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #ifndef SQQUEUE_H #define SQQUEUE_H #define OK 1 #define ERR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 typedef int Elemtype;typedef int Status;typedef struct { Elemtype data[MAXSIZE]; int front; int rear; }SqQueue; Status visit (Elemtype c) ;Status InitQueue (SqQueue *Q) ;Status ClearQueue (SqQueue *Q) ;Status QueueEmpty (SqQueue Q) ;int QueueLength (SqQueue Q) ;Status GetHead (SqQueue Q,Elemtype *e) ;Status EnQueue (SqQueue *Q,Elemtype e) ;Status DeQueue (SqQueue *Q,Elemtype *e) ;Status QueueTraverse (SqQueue Q) ;#endif
sqqueue.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 #include "stdio.h" #include "stdlib.h" #include "sqqueue.h" Status visit (Elemtype c) { printf ("%d " ,c); return OK; } Status InitQueue (SqQueue *Q) { Q->front=0 ; Q->rear=0 ; return OK; } Status ClearQueue (SqQueue *Q) { Q->front=Q->rear=0 ; return OK; } Status QueueEmpty (SqQueue Q) { if (Q.front==Q.rear) return TRUE; else return FALSE; } int QueueLength (SqQueue Q) { return (Q.rear-Q.front+MAXSIZE)%MAXSIZE; } Status GetHead (SqQueue Q,Elemtype *e) { if (Q.front==Q.rear) return ERR; *e=Q.data[Q.front]; return OK; } Status EnQueue (SqQueue *Q,Elemtype e) { if ((Q->rear+1 )%MAXSIZE == Q->front) return ERR; Q->data[Q->rear]=e; Q->rear=(Q->rear+1 )%MAXSIZE; return OK; } Status DeQueue (SqQueue *Q,Elemtype *e) { if (Q->front == Q->rear) return ERR; *e=Q->data[Q->front]; Q->front=(Q->front+1 )%MAXSIZE; return OK; } Status QueueTraverse (SqQueue Q) { int i; i=Q.front; while (i!=Q.rear) { visit(Q.data[i]); i=(i+1 )%MAXSIZE; } printf ("\n" ); return OK; } int main (int argc, char *argv[]) {int opt; int exit = OK; SqQueue test; InitQueue(&test); while (exit ) { printf ("\n======================================================================================================================== \n" ); printf (">>>请输入操作标号: 1.初始化队列; 2.队尾入队 3.队头出队 4.队列清空; 5.打印队列内元素; 0.退出;\n" ); scanf ("%d" ,&opt); switch (opt) { case 1 : { InitQueue(&test); printf ("初始化完成,目前队列为空!\n" ); } break ; case 2 : { Elemtype val; printf ("请输入入队元素的值并按回车:\n" ); scanf ("%d" ,&val); if (EnQueue(&test,val)) { printf ("入队成功!目前栈内有%d个元素。\n" ,QueueLength(test)); } } break ; case 3 : { Elemtype val; if (DeQueue(&test,&val)) { printf ("队头元素%d弹出,目前队内有%d个元素。\n" ,val,QueueLength(test)); }else { printf ("操作失败,当前队列空!" ); } } break ; case 4 : { if (ClearQueue(&test)) printf ("清空完成,目前队内有%d个元素。\n" ,QueueLength(test)); } break ; case 5 : { printf ("目前站内有%d个元素,分别是:\n" ,QueueLength(test)); QueueTraverse(test); } break ; case 0 : exit = ERR; printf ("Goodbye~\n" ); break ; default : printf ("输入错误请按标号重新输入!\n" ); } } return 0 ; }
队列的链式存储 linkqueue.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #ifndef LINKQUEUE_H #define LINKQUEUE_H #define OK 1 #define ERR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 20 #define OVERFLOW 3 typedef int Elemtype;typedef int Status;typedef struct QNode /* 结点结构 */{ Elemtype data; struct QNode *next ; }QNode,*QueuePtr; typedef struct /* 队列的链表结构 */{ QueuePtr front,rear; }LinkQueue; Status visit (Elemtype c) ;Status InitQueue (LinkQueue *Q) ;Status DestroyQueue (LinkQueue *Q) ;Status ClearQueue (LinkQueue *Q) ;Status QueueEmpty (LinkQueue Q) ;int QueueLength (LinkQueue Q) ;Status GetHead (LinkQueue Q,Elemtype *e) ;Status EnQueue (LinkQueue *Q,Elemtype e) ;Status DeQueue (LinkQueue *Q,Elemtype *e) ;Status QueueTraverse (LinkQueue Q) ;#endif
linkqueue.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 #include "stdio.h" #include "stdlib.h" #include "linkqueue.h" Status visit (Elemtype c) { printf ("%d " ,c); return OK; } Status InitQueue (LinkQueue *Q) { Q->front=Q->rear=(QueuePtr)malloc (sizeof (QNode)); if (!Q->front) { exit (OVERFLOW); printf ("OVERFLOW!" ); } Q->front->next=NULL ; return OK; } Status DestroyQueue (LinkQueue *Q) { while (Q->front) { Q->rear=Q->front->next; free (Q->front); Q->front=Q->rear; } return OK; } Status ClearQueue (LinkQueue *Q) { QueuePtr p,q; Q->rear=Q->front; p=Q->front->next; Q->front->next=NULL ; while (p) { q=p; p=p->next; free (q); } return OK; } Status QueueEmpty (LinkQueue Q) { if (Q.front==Q.rear) return TRUE; else return FALSE; } int QueueLength (LinkQueue Q) { int i=0 ; QueuePtr p; p=Q.front; while (Q.rear!=p) { i++; p=p->next; } return i; } Status GetHead (LinkQueue Q,Elemtype *e) { QueuePtr p; if (Q.front==Q.rear) return ERR; p=Q.front->next; *e=p->data; return OK; } Status EnQueue (LinkQueue *Q,Elemtype e) { QueuePtr s=(QueuePtr)malloc (sizeof (QNode)); if (!s) exit (OVERFLOW); s->data=e; s->next=NULL ; Q->rear->next=s; Q->rear=s; return OK; } Status DeQueue (LinkQueue *Q,Elemtype *e) { QueuePtr p; if (Q->front==Q->rear) return ERR; p=Q->front->next; *e=p->data; Q->front->next=p->next; if (Q->rear==p) Q->rear=Q->front; free (p); return OK; } Status QueueTraverse (LinkQueue Q) { QueuePtr p; p=Q.front->next; while (p) { visit(p->data); p=p->next; } printf ("\n" ); return OK; } int main (int argc, char *argv[]) {int opt; int exit = OK; LinkQueue test; InitQueue(&test); while (exit ) { printf ("\n======================================================================================================================== \n" ); printf (">>>请输入操作标号: 1.初始化队列; 2.队尾入队 3.队头出队 4.队列清空; 5.打印队列内元素; 0.退出;\n" ); scanf ("%d" ,&opt); switch (opt) { case 1 : { InitQueue(&test); printf ("初始化完成,目前队列为空!\n" ); } break ; case 2 : { Elemtype val; printf ("请输入入队元素的值并按回车:\n" ); scanf ("%d" ,&val); if (EnQueue(&test,val)) { printf ("入队成功!目前栈内有%d个元素。\n" ,QueueLength(test)); } } break ; case 3 : { Elemtype val; if (DeQueue(&test,&val)) { printf ("队头元素%d弹出,目前队内有%d个元素。\n" ,val,QueueLength(test)); }else { printf ("操作失败,当前队列空!" ); } } break ; case 4 : { if (ClearQueue(&test)) printf ("清空完成,目前队内有%d个元素。\n" ,QueueLength(test)); } break ; case 5 : { printf ("目前站内有%d个元素,分别是:\n" ,QueueLength(test)); QueueTraverse(test); } break ; case 0 : exit = ERR; printf ("Goodbye~\n" ); break ; default : printf ("输入错误请按标号重新输入!\n" ); } } return 0 ; }
队列总结 链队列适用于需要支持任意长度的队列,且对入队、出队和删除操作都需要支持的场景,而如果对访问效率要求较高的场景,则需要考虑使用循环队列。