栈
来源:互联网 发布:校园网络规划 编辑:程序博客网 时间:2024/06/06 21:38
定义
栈是一种特殊的线性表,它只允许对线性表的表头或者表尾数据进行操作。栈的实现方式有两种,一种是顺序映像实现,还有一种是链式映像实现。栈的顺序映像实现方式通常和线性顺序表中的原理一样,只不过他只能对表尾进行操作,也就是我们熟悉的top指针放在表尾,入栈出栈操作就是在顺序表表尾增加删除结点。利用这种方式实现,需要预分配栈空间,当存储元素个数超过预分配的栈空间的时候,需要扩充。栈的链式映像实现通俗点说就是一个特定的链表,只能对链表的表头操作,也就是将head指针变为top指针,入栈出栈操作就是在表头增加和删除结点的过程。 利用这种方式实现,不需要预分配栈空间,栈空间是根据存储需求动态变化的。
栈的顺序映射实现图
栈的链式映射实现图
相关操作以及时间复杂度分析
入栈(Push)
入栈操作对于顺序实现方式和链式实现方式都是相对来说比较容易的,因为都有top指针指向栈顶,因此入栈的操作只要将数据放入top指针指向的结点空间,然后top指针自加1即可。因此时间复杂度显然是O(1)。这两种实现方式唯一的不同点就是,前者入栈前需要判断,栈是否已经满了,如果满了,需要扩充栈的容量。后者则不需要判断是否栈满,只需要申请新的结点空间,插入即可。
出栈(Pop)
出栈操作对于顺序实现方式和链式实现方式也都是相对比较容易的,因为都有top指针指向栈顶,只要将top指针自减1,然后获取top指针指向存储单元的数据即可。因此时间复杂度显然也是O(1)。这两种实现方式唯一的不同点是,后者需要将原来top指针指向的存储结点给free掉,避免内存空间的浪费。而前者不需要做任何操作。
获取栈顶元素(GetTop)
获取栈顶元素其实和出栈差不多,只不过唯一的区别是top指针不要自减1,而是利用(top-1),去获取栈顶元素,因为它不需要将栈顶元素给弹出,所以仍然要保护栈结构保持不变。时间复杂度也是O(1)。
获取栈内元素个数(GetLength)
获取栈内元素个数两种实现方式完全不同。由于顺序表的特性,完全可以用top指针-base指针(base指针指向的是栈底元素),来求得栈内元素个数,因此时间复杂度为O(1);而链式结构,是不是意味着通过top指针往下遍历才能获取呢?显然不是,我们通过将栈内元素个数的这个信息保存在top指针指向结点数据域内,这样就可以通过top->data获取栈内元素个数。这样使得时间复杂度也变为O(1)。
判断栈是否为空
顺序实现方式只需要判断top指针是否与base指针相等,如果相等即为空;而链式实现方式则需要通过top->data是否等于0,如果相等即为空;两者的时间复杂度都是O(1)。
清空栈(Clear)
链式结构的清空栈和销毁栈其实是一样的,具体看销毁栈这一部分。顺序结构的清空栈,就是将top=base即可,也就表明了栈已经为空,时间复杂度为O(1)。
销毁栈(Destroy)
对于顺序实现方式来说,只要将base指针指向申请的连续内存空间给free掉,然后将base指针和top指针置为NULL即可;时间复杂度为O(1)。而对于链式存储方案来说,因为内存空间不连续,所以只能通过遍历的方式从top到链表末尾,一个个结点free掉,然后将top->data = 0, top->next=NULL;完成销毁过程,时间复杂度显然是O(n)。
实现代码
栈的顺序映像实现方式
#include<stdio.h>#include<stdlib.h>#define INIT_SIZE 10#define INCREMENT_SIZE 5#define ERROR -50000/* * 栈结构体,包含两个指针分别为base指针和top指针 * base指针:指向栈底 * top指针:指向栈顶 * apacity: 栈的存储容量(不是指栈内目前元素的个数) */typedef struct Stack{ int *base; int *top; int capacity;}Stack;/* * 初始化栈结构 */void init_stack(Stack *stack){ stack->base = (int *)malloc(INIT_SIZE*sizeof(int)); stack->top = stack->base; stack->capacity = INIT_SIZE;}/* * 入栈 */void push(Stack *stack, int value){ if(stack->top - stack->base >= stack->capacity){ stack->base = (int *)realloc(stack->base, (stack->capacity + INCREMENT_SIZE)*sizeof(int)); stack->top = stack->base + stack->capacity; stack->capacity += INCREMENT_SIZE; } // 入栈 *(stack->top) = value; stack->top++;}/* * 出栈 */int pop(Stack *stack){ if(stack->top == stack->base) return ERROR; return *(--stack->top);}/* * 判断栈是否为空 */int is_empty(Stack stack){ return stack.top == stack.base;}/* * 获取栈顶元素 */int get_top(Stack stack){ if(stack.top == stack.base) return ERROR; return *(stack.top-1);}/* * 销毁栈 */void destroy(Stack *stack){ free(stack->base); stack->base = NULL; stack->top = NULL; stack->capacity = 0;}/* * 获取栈内元素个数 */int get_length(Stack stack){ return stack.top - stack.base;}/* * 清空元素 */void clear(Stack *stack){ stack->top = stack->base;}/* * 从栈底到栈顶遍历打印 * 这里绝对不要用栈指针参数,否则会改变栈空间的 */void print_stack_traverse(Stack stack){ while(stack.base < stack.top){ printf("%d ", *stack.base++); } printf("\n");}int main(){ Stack stack; init_stack(&stack); for(int i=0; i<10; i++) push(&stack, i); print_stack_traverse(stack); printf("The length of stack %d\n", get_length(stack)); printf("The capacity of stack %d\n", stack.capacity); int top = pop(&stack); printf("after pop element %d\n", top); print_stack_traverse(stack); for(int i = 100; i<=115; i++) push(&stack, i); print_stack_traverse(stack); printf("The length of stack %d\n", get_length(stack)); printf("The capacity of stack %d\n", stack.capacity); int gtop = get_top(stack); printf("get top element %d\n", gtop); print_stack_traverse(stack); printf("stack is %s\n", is_empty(stack)?"empty":"not empty"); clear(&stack); printf("after clear stack\n"); printf("stack is %s\n", is_empty(stack)?"empty":"not empty"); destroy(&stack); printf("after destroy stack\n"); printf("The capacity of stack %d\n", stack.capacity); return 0;}
栈的链式映像实现方式
#include<stdio.h>#include<stdlib.h>typedef struct SNode *PSNode;#define ERROR -1/* * 栈的链式结点 * data: 在top指针结点内表示的是栈内元素个数,在一般结点内表示结点元素值 * next:链表的后继 */typedef struct SNode{ int data; PSNode next;}SNode, *PSNode;/* * 栈的初始化 */void init_stack(PSNode *top){ (*top) = (PSNode) malloc(sizeof(SNode)); (*top)->data = 0; (*top)->next = NULL;}/* * 入栈 */void push(PSNode top, int value){ PSNode node = (PSNode)malloc(sizeof(SNode)); node->data = value; node->next = top->next; top->next = node; top->data++;}/* * 出栈 */int pop(PSNode top){ if(!top->next) return ERROR; PSNode topNode = top->next; int data = topNode->data; top->next = topNode->next; free(topNode); top->data--; return data;}/* * 获取栈顶元素值 */int get_top(PSNode top){ if (!top->next) return ERROR; return top->next->data;}/* * 判断栈是否为空 */int is_empty(PSNode top){ return top->data == 0;}/* * 获取栈内元素个数 */int get_length(PSNode top){ return top->data;}/* * 栈的链式存储结构清空和销毁都差不多,都是一边改top指针一边回收结点 */void clear(PSNode top){ while(top->next){ PSNode empty = top->next; top->next = top->next->next; free(empty); } top->data = 0;}void print_stack(PSNode top){ PSNode p = top->next; printf("Stack from top to base:"); while(p){ printf("%d ", p->data); p = p->next; } printf("\n");}int main(){ PSNode top; init_stack(&top); for(int i=0; i<10; i++) push(top, i); print_stack(top); printf("The length of stack %d\n", get_length(top)); int topElement = pop(top); printf("after pop element %d\n", topElement); printf("The length of stack %d\n", get_length(top)); print_stack(top); int gtop = get_top(top); printf("get top element %d\n", gtop); printf("stack is %s\n", is_empty(top)?"empty":"not empty"); clear(top); printf("after clear stack\n"); printf("stack is %s\n", is_empty(top)?"empty":"not empty"); printf("The length of stack %d\n", get_length(top)); return 0;}
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- 栈
- [图像] 奇异值分解与隐性语义分析
- JVM分析工具链(二) - jmap和jhat
- Java学习笔记(87)-----------十篇必读的Java文章
- yii执行流程
- Redis学习记录之Connection(连接)(二十一)
- 栈
- 手机浏览器javascript事件及css总结
- [Deeplearning]RBM-hinton代码解读
- NSDictionary和NSMutableDictionary的基本使用
- Java学习笔记(88)-----------值得拥有的10本书
- AJAX发送POST、GET请求
- SSL/TLS Configuration HOW-TO Apache Tomcat 7
- yii计划任务
- 月薪3万是怎么修炼成的?