赞
踩
限定仅在表尾进行插入和删除操作的线性表称之为栈
把允许插入和删除的一端称为栈顶(top),另一端称为栈底( bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出( Last In First Out)的线性表,简称LIFO结构。
栈的插入操作,叫作进栈,也称压栈、入栈。
栈的删除操作,叫作出栈,也有的叫作弹栈。
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 5 typedef int datatype; typedef struct { datatype data[MAXSIZE]; int top; }sq_stack_t; //创建 sq_stack_t *sqstack_create(void) { sq_stack_t *s; s = (sq_stack_t *)malloc(sizeof(sq_stack_t)); if (s == NULL) return NULL; s->top = -1; return s; } //销毁 void sqstack_destroy(sq_stack_t *sq_stack) { free(sq_stack); } //判断是否为空 int sqstack_is_empty(sq_stack_t *sq_stack) { return (sq_stack->top == -1); } //入栈 int sqstack_push(sq_stack_t *sq_stack, datatype data) { if (sq_stack->top == MAXSIZE-1) return -1; sq_stack->top++; sq_stack->data[sq_stack->top] = data; return 0; } //出栈 int sqstack_pop(sq_stack_t *sq_stack, datatype *data) { if (sqstack_is_empty(sq_stack)) return -1; *data = sq_stack->data[sq_stack->top]; sq_stack->top--; return 0; } //遍历打印数据 void sqstack_traversal(sq_stack_t *sq_stack) { int i; if (sqstack_is_empty(sq_stack)) return; for (i = 0; i <= sq_stack->top; i++) printf("%d ", sq_stack->data[i]); printf("\n"); } int main(void) { sq_stack_t *sq_stack = NULL; datatype data; int i, ret; sq_stack = sqstack_create(); if (sq_stack == NULL) { printf("sqstack create failed \n"); exit(1); } for (i = 0; i<MAXSIZE; i++) { int ret = sqstack_push(sq_stack, i); if (ret != 0) { printf("sqstack push failed %d\n", ret); break; } } sqstack_traversal(sq_stack); ret = sqstack_pop(sq_stack, &data); if (ret != 0) { printf("sqstack_pop failed %d \n", ret); } sqstack_traversal(sq_stack); sqstack_destroy(sq_stack); }
栈的链式存储结构,简称为链栈
链栈本质就是一个链表的首部插入、删除或尾部插入、删除的实现;首部操作用单链表比较好;尾部操作用双环链表更方便实现
下面例程用的是单链表首部插入、删除
进栈操作
出栈操作
代码实现
#include <stdio.h> #include <stdlib.h> typedef int datatype; typedef struct _lsnode { datatype data; struct _lsnode *next; }linkstack_t; linkstack_t *ls_create(void) { linkstack_t *ls = NULL; ls = (linkstack_t *)malloc(sizeof(linkstack_t)); if (ls == NULL) return NULL; ls->next = NULL; return ls; } void ls_destroy(linkstack_t *ls) { linkstack_t *p = NULL, *q = NULL; for (p=ls->next; p!=NULL; p=p->next) { q = p; free(q); } free(ls); } int ls_push(linkstack_t *ls, datatype data) { linkstack_t *new = NULL; new = (linkstack_t *)malloc(sizeof(linkstack_t)); if (new == NULL) return -1; new->data = data; new->next = ls->next; ls->next = new; return 0; } int ls_pop(linkstack_t *ls, datatype *data) { linkstack_t *new = ls->next; if (new == NULL) return -1; *data = new->data; ls->next = ls->next->next; free(new); return 0; } void ls_traversal(linkstack_t *ls) { linkstack_t *ptr=ls->next; for (ptr = ls->next; ptr != NULL; ptr=ptr->next) { printf("%d ", ptr->data); } printf("\n"); } int main(void) { linkstack_t *ls=NULL; int i, ret; datatype data; ls = ls_create(); if (ls == NULL) { printf("ls_create failed \n"); exit(1); } for (i = 1; i < 16; i++) { ret = ls_push(ls, i); if (ret != 0) { printf("ls_push failed %d\n", ret); break; } } ls_traversal(ls); ret = ls_pop(ls, &data); if (ret != 0) { printf("ls_pop failed %d\n", ret); } printf("data:%d \n",data); ls_traversal(ls); ret = ls_pop(ls, &data); if (ret != 0) { printf("ls_pop failed %d\n", ret); } printf("data:%d \n",data); ls_traversal(ls); ret = ls_pop(ls, &data); if (ret != 0) { printf("ls_pop failed %d\n", ret); } printf("data:%d \n",data); ls_traversal(ls); ls_destroy(ls); ls_traversal(ls); exit(0); }
头尾相接的顺序存储结构称为循环队列。
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 5 typedef int datatype; typedef struct { datatype data[MAXSIZE]; int front; //队列头 int rear; //队列尾 }sq_queue_t; //创建 sq_queue_t *squeue_create(void) { sq_queue_t *queue; queue = (sq_queue_t *)malloc(sizeof(sq_queue_t)); if (queue == NULL) return NULL; queue->front = queue->rear = 0; //都指向下标为0的空间 return queue; } //销毁 sq_queue_t squeue_destroy(sq_queue_t *queue) { free(queue); } //判断是否满 static int squeue_is_fill(sq_queue_t *queue) { return ((queue->rear+1)%MAXSIZE == queue->front); } //判断是否为空 static int squeue_is_empty(sq_queue_t *queue) { return (queue->front == queue->rear); } //入队 int squeue_en(sq_queue_t *queue, datatype data) { if (squeue_is_fill(queue)) return -1; queue->rear = (queue->rear+1)%MAXSIZE; queue->data[queue->rear] = data; return 0; } //出队 int squeue_de(sq_queue_t *queue, datatype *data) { if (squeue_is_empty(queue)) return -1; *data = queue->data[queue->front]; queue->front = (queue->front+1)%MAXSIZE; return 0; } //清理队列的数据 void squeue_clear_data(sq_queue_t *queue) { queue->front = queue->rear; } //得到队列有效元素个数 static int squeue_get_elemlen(sq_queue_t *queue) { return (queue->rear-queue->front+MAXSIZE)%MAXSIZE; } //遍历 void squeue_traversal(sq_queue_t *queue) { int i; if (squeue_is_empty(queue)) return; i = queue->front; while (i != queue->rear) { printf("%d ", queue->data[i]); i = (i+1)%MAXSIZE; } printf("\n"); } int main(void) { sq_queue_t *queue = NULL; int i, ret; datatype data; queue = squeue_create(); if (queue == NULL) { printf("squeue_create failed \n"); exit(1); } for (i = 1; i < MAXSIZE; i++) { ret = squeue_en(queue, i); if (ret != 0) { printf("squeue_en failed %d\n", ret); break; } } squeue_traversal(queue); ret = squeue_de(queue, &data); if (ret != 0) { printf("squeue_de failed %d\n", ret); } printf("data:%d, queue_len:%d\n", data, squeue_get_elemlen(queue)); squeue_traversal(queue); ret = squeue_de(queue, &data); if (ret != 0) { printf("squeue_de failed %d\n", ret); } printf("data:%d, queue_len:%d\n", data, squeue_get_elemlen(queue)); squeue_traversal(queue); squeue_clear_data(queue); printf("queue_len:%d\n", squeue_get_elemlen(queue)); squeue_destroy(queue); exit(0); }
小结:从这一段讲解,大家应该发现,单是顺序存储,若不是循环队列,,算法的时间性能是不高的,但循环队列又面临着数组可能会溢出的问题,所以我们还需要研究一下不需要担心队列长度的链式存储结构。
typedef int QElemType;
typedef struct QNode //结点结构
{
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct //队列的链表结构
{
QueuePtr front, rear; //队头、队尾指针
}LinkQueue;
int en_queue(LinkQueue *Q, QElemType e)
{
QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
if (!s)
return -1;
s->data = e;
s->next = NULL;
Q->rear->next = s; //把拥有元素e新结点s赋值给原队尾结点的后继,见上图①
Q->rear = s; //把当前的s设置为队尾结点,rear指向s,见上图中②
return 0;
}
int de_queue(LinkQueue *Q, QElemType *e) { QueuePtr p; if (Q->front == Q->rear) return -1; p = Q->front->next; //将欲删除的队头结点暂存给p,见上图中① *e = p->data; //将欲删除的队头结点的值赋值给e Q->front->next = p->next; //将原队头结点后继p->next 赋值给头结点后继,见上图中② if (Q->rear == p) //若队头是队尾,则删除后将rear指向头结点,见上图中③ Q->rear = Q->front; free(p); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。