C/C++数据结构-完整代码栈(栈的顺序存储,栈的链式存储,就近匹配,中缀表达式和后缀表达式)
Posted 蓝盒子itbluebox
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++数据结构-完整代码栈(栈的顺序存储,栈的链式存储,就近匹配,中缀表达式和后缀表达式)相关的知识,希望对你有一定的参考价值。
C/C++数据结构-完整代码(一)数据结构的理论,线性表(动态数组,链表)(完整的算法代码-增删改查-代码解析+运行结果解析) | |
C/C++数据结构-完整代码(二)栈(栈的顺序存储,栈的链式存储,就近匹配,中缀表达式和后缀表达式) | |
C/C++数据结构-完整代码(三)队列【Queue】(顺序存储,链式存储)增删改查 | |
C/C++数据结构-完整代码(四)队列【Queue】(树和二叉树)(二叉树代码实现) |
一、受限线性表:栈(Stack)
1、栈的顺序存储
(1)栈的基本概念
-
概念:
首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。
只不过它是一种特殊的线性表而已。
定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。 -
特性(先进后出的数据结构)
它的特殊之处在于限制了这个线性表的插入和删除的位置,它始终只在栈顶进行。这也
就使得∶栈底是固定的,最先进栈的只能在栈底加
栈不可以遍历、只有栈顶元素可以被外界访问到(遍历:不重复不遗漏访问容器中的所有数据
遍历算法属于非质变算法) -
操作
栈的插入操作(push),叫做进栈,也成压栈。(在进栈的时候可以统计个数)
关似子弹入弹夹(如下图所示)栈的删除操作,叫做出栈,
也有的叫做弹栈(pop),退栈。(在出栈的时候不可以统计个数(size))
如同弹夹中的子弹出夹(如下图所示)
(2)栈的设计(栈是属于一种先进后出的数据结构)
- 栈顶在数组的首地址还是尾地址?
钱顶设计在尾地址(数组的尾部进行频繁的插入删除效率比头部更高)
struct SStack{
void * data[1024];
int m_size;//栈的大小(栈当中元素个数)
}
(3)栈的顺序存储
//栈的结构体
struct SStack{
void * data[MAX];//栈的数组
//栈的元素个数
int m_Size;
};
typedef void * seqStack;
//初始化栈
seqStack init_SeqStack(){
struct SStack * stack = malloc (sizeof (struct SStack));
if(stack == NULL){
return NULL;
}
//清空数组当中的元素
//将栈当中的数据清空,清空为0,清空的大小为 栈当中每个元素sizeof(void *)乘以每个元素的大小
memset (stack->data,0,sizeof(void *) *MAX );
stack->m_Size = 0;
return stack;
}
//入栈
void push_SeqStack(seqStack stack,void * data){
if(stack == NULL){
return;
}
if(data == NULL){
return;
}
//判断栈是否已经满了,如果满了不可以再入栈了
struct SStack * myStack = stack;
if(myStack->m_Size == MAX){
return;
}
myStack->data[myStack->m_Size] = data;//入栈尾插
myStack->m_Size++;//更新栈的大小
}
//出栈
void pop_SeqStack(seqStack stack){
if(stack == NULL){
return;
}
//如果是空栈不执行空栈
struct SStack * myStack = stack;
if(myStack->m_Size <= 0){
return;
}
//执行出栈
myStack->data[myStack->m_Size-1] = NULL;
//更新栈的大小
myStack->m_Size -- ;
}
//获取栈顶元素
void * top_SeqStack(seqStack stack){
if(stack == NULL){
return NULL;
}
struct SStack * myStack = stack;
//如果是空栈
if(myStack->m_Size == 0){
return NULL;
}
return myStack->data[myStack->m_Size-1];
}
//栈的大小
int size_SeqStack(seqStack stack){
if(stack == NULL){
return -1;
}
struct SStack * myStack = stack;
return myStack->m_Size;
}
//判断栈是否为空
int isEmpty_SeqStack(seqStack stack){
if(stack == NULL){
return -1;//真
}
struct SStack * myStack = stack;
if(myStack->m_Size <= 0){
return -1;//真
}
return 0;//返回假代表不是空栈
}
//销毁栈
void destory_SeqStack(seqStack stack){
if(stack == NULL)
{
return;
}
free (stack);
stack = NULL;
}
测试代码全部代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LINE "---------------------------------------\\n"
#define MAX 1024
//栈的结构体
struct SStack{
void * data[MAX];//栈的数组
//栈的元素个数
int m_Size;
};
typedef void * seqStack;
//初始化栈
seqStack init_SeqStack(){
struct SStack * stack = malloc (sizeof (struct SStack));
if(stack == NULL){
return NULL;
}
//清空数组当中的元素
//将栈当中的数据清空,清空为0,清空的大小为 栈当中每个元素sizeof(void *)乘以每个元素的大小
memset (stack->data,0,sizeof(void *) *MAX );
stack->m_Size = 0;
return stack;
}
//入栈
void push_SeqStack(seqStack stack,void * data){
if(stack == NULL){
return;
}
if(data == NULL){
return;
}
//判断栈是否已经满了,如果满了不可以再入栈了
struct SStack * myStack = stack;
if(myStack->m_Size == MAX){
return;
}
myStack->data[myStack->m_Size] = data;//入栈尾插
myStack->m_Size++;//更新栈的大小
}
//出栈
void pop_SeqStack(seqStack stack){
if(stack == NULL){
return;
}
//如果是空栈不执行空栈
struct SStack * myStack = stack;
if(myStack->m_Size <= 0){
return;
}
//执行出栈
myStack->data[myStack->m_Size-1] = NULL;
//更新栈的大小
myStack->m_Size -- ;
}
//获取栈顶元素
void * top_SeqStack(seqStack stack){
if(stack == NULL){
return NULL;
}
struct SStack * myStack = stack;
//如果是空栈
if(myStack->m_Size == 0){
return NULL;
}
return myStack->data[myStack->m_Size-1];
}
//栈的大小
int size_SeqStack(seqStack stack){
if(stack == NULL){
return -1;
}
struct SStack * myStack = stack;
return myStack->m_Size;
}
//判断栈是否为空
int isEmpty_SeqStack(seqStack stack){
if(stack == NULL){
return -1;//真
}
struct SStack * myStack = stack;
if(myStack->m_Size <= 0){
return -1;//真
}
return 0;//返回假代表不是空栈
}
//销毁栈
void destory_SeqStack(seqStack stack){
if(stack == NULL)
{
return;
}
free (stack);
stack = NULL;
}
//测试
struct Person{
char name[64];
int age;
};
void test01(){
//准备数据
struct Person p1 = {"aaa",10};
struct Person p2 = {"bbb",20};
struct Person p3 = {"ccc",30};
struct Person p4 = {"ddd",40};
struct Person p5 = {"fff",50};
//初始化栈
seqStack stack = init_SeqStack();
push_SeqStack (stack,&p1);
push_SeqStack (stack,&p2);
push_SeqStack (stack,&p3);
push_SeqStack (stack,&p4);
push_SeqStack (stack,&p5);
printf("stack size = %d\\n", size_SeqStack (stack));
void * ss = top_SeqStack(stack);
printf ("%s\\n",LINE);
printf ("stack top = %s\\n",ss);
printf ("%s\\n",LINE);
while (isEmpty_SeqStack (stack) == 0){//如果栈不为空 ,进行访问栈顶的元素并且出栈
struct Person * pTop= top_SeqStack(stack);
printf ("Top stack : Name = %s , Age = %d \\n",pTop->name,pTop->age);
printf ("Pop stack\\n");
pop_SeqStack (stack);
}
printf ("%s\\n",LINE);
printf("stack size = %d\\n", size_SeqStack (stack));
printf ("%s\\n",LINE);
printf ("destory_SeqStack\\n");
destory_SeqStack(stack);
printf("stack size = %d\\n", size_SeqStack (stack));
printf ("%s\\n",LINE);
}
int main(){
test01();
return 0;
}
运行结果
2、栈(Stack)栈的链式存储
//节点的结构体
struct StackNode{
struct StackNode * next;//只维护指针域
};
//链式的栈结构体
struct LStack{
struct StackNode pHeader;//头节点
int m_Size;//栈的大小
};
//初始化栈
typedef void * LinkStack;
//初始化栈
LinkStack init_LinkStack(){
struct LStack * myStack = malloc (sizeof( struct LStack ));
if(myStack == NULL){
return NULL;
}
myStack->pHeader.next = NULL;
myStack->m_Size = 0;
return myStack;
}
//入栈
void push_LinkStack(LinkStack stack,void * data){
if(stack == NULL){
return;
}
if(data == NULL){
return;
}
//入栈 就是 头插入
struct LStack * myStack = stack;//(还原为原来的数据类型,因为用户只知道LinkStack而不知道LStack)
//获取到用户数据的前四个字节
struct StackNode * myNode = data;
//插入节点
myNode->next = myStack->pHeader.next;//将当前节点的指针域指向链表的头结点
myStack->pHeader.next = myNode;//头结点指向插入的节点
//更新栈的大小
myStack->m_Size++;
}
//出栈
void pop_LinkStack(LinkStack stack){
if(stack == NULL){
return;
}
struct LStack * myStack = stack;
//如果是空栈就不出栈
if(myStack->m_Size <= 0){
return;
}
//保存第一个有数据的节点 栈顶的元素
struct StackNode * pFirst = myStack->pHeader.next;
myStack->pHeader.next = pFirst->next;//将第二个节点指针域当中指向第一个结点指针域指向的地方也就是下一个元素的地址
//更新一下栈的大小
myStack->m_Size--;
}
//返回栈顶元素
void * top_LinkStack(LinkStack stack){
if(stack == NULL){
return NULL;
}
struct LStack * myStack = stack;
if(myStack->m_Size <= 0){
return NULL;
}
return myStack->pHeader.next;//将第一个有数据的结点返回就可以了
}
//返回栈的大小
int size_LinkStack(LinkStack stack){
if(stack == NULL){
return -1;
}
struct LStack * myStack = stack;
return myStack->m_Size;
}
//判断是否为空
int isEmpty_LinkStack(LinkStack stack){
if(stack == NULL){
return -1;
}
struct LStack * myStack = stack;
if(myStack->m_Size <=0){
return 1;
}
return 0;
}
//销毁
void destory_LinkStack(LinkStack stack){
if(stack == NULL){
return;
}
free (stack);
stack = NULL;
}
//测试
struct Person{
char name[64];
int age;
};
测试代码以及全部代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define LINE "---------------------------------------\\n"
#define MAX 1024
//节点的结构体
struct StackNode{
struct StackNode * next;//只维护指针域
};
//链式的栈结构体
struct LStack{
struct StackNode pHeader;//头节点
int m_Size;//栈的大小
};
typedef void * LinkStack;
//初始化栈
LinkStack init_LinkStack(){
struct LStack * myStack = malloc (sizeof( struct LStack ));
if(myStack == NULL){
return NULL;
}
myStack->pHeader.next = NULL;
myStack->m_Size = 0;
return myStack;
}
//入栈
void push_LinkStack(LinkStack stack,void * data){
if(stack == NULL){
return;
}
if(data == NULL){
return;
}
//入栈 就是 头插入
struct LStack * myStack = stack;//(还原为原来的数据类型,因为用户只知道LinkStack而不知道LStack)
//获取到用户数据的前四个字节
struct StackNode * myNode = data;
//插入节点
myNode->next = myStack->pHeader.next;//将当前节点的指针域指向链表的头结点
myStack->pHeader.next = myNode;//头结点指向插入的节点
//更新栈的大小
myStack->m_Size++;
}
//出栈
void pop_LinkStack(LinkStack stack){
if(stack == NULL){
以上是关于C/C++数据结构-完整代码栈(栈的顺序存储,栈的链式存储,就近匹配,中缀表达式和后缀表达式)的主要内容,如果未能解决你的问题,请参考以下文章
C/C++数据结构-完整代码队列Queue(顺序存储,链式存储)增删改查
C/C++|DataStructure栈与队列之栈的顺序存储结构