目录
一、栈的逻辑结构
1.栈定义
2.栈与线性表的区别与联系
3.栈的相关运算
4.要对栈状态进行标示,仅需要一个参数即可。
二、顺序栈
1.顺序栈数据结构
2.顺序栈初始化
3.判断栈空和栈满
4.压栈
5.弹栈
6.取栈顶元素
7.顺序栈进行数制转换,实现10进制转8进制
三、链栈
1.链栈数据结构定义
2.初始化
3.判断栈空
4.压栈
5.弹栈
6.链栈进行数制转换,实现10进制转8进制
顺序表相关知识:https://blog.csdn.net/qq_41291253/article/details/89317523
链表相关知识:https://blog.csdn.net/qq_41291253/article/details/89218736
new 和 malloc区别:https://www.cnblogs.com/ywliao/articles/8116622.html
栈(Stack)是一种特殊的线性表,它所有的插入和删除都限制在表的同一端进行。
栈中允许进行插入、删除操作的一端叫做栈顶(Top),另一端则叫做栈底(Bottom)。当栈中没有元素时,称之为空栈。栈的插入运算通常称为压栈、进栈或入栈(Push),栈的删除运算通常称为弹栈或出栈(Pop)。示意图如下
(1)栈是特殊的线性表
(2)栈的插入与删除运算只能在栈顶进行,而线性表的插入和删除运算可在线性表中的任意位置进行
(1)栈的初始化操作:建立一个空栈 S。
(2)判栈空:判断栈是否为空。
(3)取栈顶元素:取得栈顶元素的值。
(4)压栈:在栈S中插入元素e,使其成为新的栈顶元素。
(5)弹栈:删除栈 S的栈顶元素。
在栈的大小已经确定的前提下,有栈空、栈满、非空非满三种情况。根据栈的定义,每次进栈的数据元素,都放在栈顶元素之前而成为新的栈顶元素,每次退栈的数据元素都是当前栈顶元素,所以栈中内容的变化只需要一个栈顶指针的指示即可。
栈的顺序存储结构需要使用一个数组和一个整形变量来实现。利用数组来顺序存储栈中的所有元素,利用整形变量来存储栈顶元素的下标位置。
/*=====================================
函数功能:栈结构体定义
函数输入:无
函数输出:无
====================================*/
typedef struct Stack
{
int data[Stack_Size]; //顺序栈(数组)大小
int top; //栈顶位置(栈顶在数组中的下标)
}SeqStack;
对栈初始化,将栈顶指针置为-1;
/*=====================================
函数功能:顺序栈置空栈(初始化)
函数输入:顺序栈地址
函数输出:无
====================================*/
void initialize_SqStack(SeqStack *s) //要更改栈内数据,需要传址调用,或者采取引用方式
{
s->top = -1;
}
判断栈空,查找栈中是否有元素
判断栈满,查看栈顶指针是否达到最大值
/*=====================================
函数功能:判断栈是否为空
函数输入:顺序栈地址
函数输出:1——栈空;0——栈非空
====================================*/
int StackEmpty_SqStack(SeqStack *s)
{
return(s->top == -1); //此处简化运行代码,不需要进行 if 判断
}
/*=====================================
函数功能:判断栈是否满
函数输入:顺序栈地址
函数输出:1——栈满;0——栈非满
====================================*/
int StackCompletely(SeqStack *s)
{
return(s->top == Stack_Size - 1);
}
将数值1、2、3依次压入栈中,示意图如下所示。数字2进栈前,栈顶指针Top指向栈顶元素1所在的位置,要将2入栈,先将栈顶指针Top加1,指向1所在的上一个位置,再把2放入此单元中。
/*=====================================
函数功能:压栈
函数输入:顺序栈地址,压栈数据
函数输出:0——栈溢出,1——操作正常
====================================*/
int Pushu_SqStack(SeqStack *s, int n) //修改栈内数据,此处必选传址或引用
{
if(StackCompletely(s)) //判断栈满
return false;
else
{ s->top++;
s->data[s->top] = n;
}
return true;
}
顺序栈出栈操作后不需要删除原来的栈顶元素值。因为栈顶元素的位置是通过栈顶指针标示的,不是靠判断栈中的元素值是否存在来确定栈顶的位置。同时也不会对下一次进栈操作产生影响,因为进栈操作是“写操作”,即对原来的单元空间进行覆盖。
/*=====================================
函数功能:出栈
函数输入:顺序栈地址,(弹出数据)
函数输出:0——栈空,1——操作正常
注意:弹出数据可以根据程序员选择是否
需要保存,如不需要删除即可。
====================================*/
int Pop_SqStack(SeqStack *s, int *e)
{
if(StackEmpty_SqStack(s))
return false;
else
{
*e = s->data[s->top];
s->top--;
}
return true;
}
和出栈操作类似,只是指针不发生变化。
/*=====================================
函数功能:取栈顶元素
函数输入:顺序栈地址,栈顶数据
函数输出:0——栈空,1——操作正常
====================================*/
int Get_SqStack(SeqStack *s, int *e)
{
if(StackEmpty_SqStack(s))
return false;
else
{
*e = s->data[s->top];
}
return true;
}
#include
#include
/*=====================================
函数功能:数制转换
转换公式:N = (n / d) * d + n % d
n n / d n % d
1348 168 4 ——8进制最低位
168 21 0 ——8进制第二位
21 2 5 ——8进制第三位
2 0 2 ——8进制第四位
函数输入:顺序栈地址,转换前数据
函数输出:转换后数据
// ====================================*/
void conversion_S(SeqStack *S, int n)
{
int e;
while(n)
{
Pushu_SqStack(S, n % 8);
n = n / 8;
}
while(!StackEmpty_SqStack(S))
{
Pop_SqStack(S, &e);
printf("%d", e);
}
}
int main(int argc, const char * argv[])
{
SeqStack s;
initialize_SqStack(&s);
conversion_S(&s, 1348);
std::cout<
顺序栈存在栈满以后就不能在进栈的问题,这是因为用了定长的数组存储栈的元素。解决的方法可以是使用链式存储结构,让栈空间可以动态扩充。
栈的链式存储结构成为链栈,它是运算受限的单链表,其插入和删除操作仅限制在表头位置上进行。由于只能在链表头部进行操作,故链栈没有必要像链表那样附加头结点。栈顶指针就是链表的头指针。
/*=============================================
函数功能:链栈结构体定义
函数输入:无
函数输出:无
============================================*/
typedef struct CLinkStack
{
int data;
CLinkStack *next; //链指针
}LinkStack;
LinkStack *top; //链顶指针
栈底指针不做实际用途,仅用作判断栈空,不存储数据。
/*=============================================
函数功能:链栈的初始化(栈顶指针不存储数据)
函数输入:链栈指针
函数输出:栈顶指针
============================================*/
LinkStack *InitLStack(LinkStack *s)
{
s = new LinkStack; //在自由存储区中分配内存
//s = (LinkStack*)malloc(sizeof(LinkStack)); //在堆中分配内存,两种方法均可
s->next = NULL;
top = s;
return top;
}
/*=============================================
函数功能:链栈是否为空
函数输入:链栈头指针
函数输出:1——链栈为空;0——链栈非空
============================================*/
int LinkStackEmpty(LinkStack *top)
{
return (top->next == NULL);
}
链栈栈底为链表的表尾,栈顶为链表的表头
/*=============================================
函数功能:链栈的压栈
函数输入:(栈顶指针),压栈元素
函数输出:栈顶指针
是否需要返回栈顶指针:传址调用是在同地址中的内容传递,
若子函数中修改了传递的地址,则此被修改的地址是无法
通过“传址”传送的。此种情形和 top 的指向未发生变化
,但是top 指向单元的内容发生变化有所区别。
============================================*/
LinkStack *PushLStack(LinkStack *top, int n)
{
LinkStack *s = new LinkStack; //在自由存储区分配内存
s->data = n;
s->next = top;
top = s;
return top; //top 地址发生改变
}
/*=============================================
函数功能:链栈的弹栈
函数输入:(栈顶指针),压栈元素
函数输出:栈顶指针
============================================*/
LinkStack *PopLStack(LinkStack *top, int *datap)
{
if(top != NULL)
{
*datap = top->data;
LinkStack *s;
s = top;
top = top->next;
delete s;
}
return top;
}
//
// main.cpp
// 栈的应用数制转换
//
// Created by 一丁 on 2019/4/17.
// Copyright © 2019年 LGD. All rights reserved.
//
#include
#include
//#include "LinkStack.h"
//#include "Stack.h"
/*=====================================
函数功能:数制转换
转换公式:N = (n / d) * d + n % d
n n / d n % d
1348 168 4 ——8进制最低位
168 21 0 ——8进制第二位
21 2 5 ——8进制第三位
2 0 2 ——8进制第四位
函数输入:顺序栈地址,转换前数据
函数输出:转换后数据
// ====================================*/
void conversion_L(LinkStack *top, int n)
{
int e;
while(n)
{
top = PushLStack(top, n % 8); //要把返回值地址赋值给 top,因为在压栈后 top 地址发生了变化
n = n / 8;
}
while(!LinkStackEmpty(top))
{
top = PopLStack(top, &e);
printf("%d", e);
}
}
int main(int argc, const char * argv[])
{
LinkStack l;
InitLStack(&l);
conversion_L(&l, 1348);
return 0;
}