栈/队列的基本概念及相应操作
一、栈的定义及使用
栈的定义:栈是仅限于在表尾进行插入和删除操作的线性表。我们通常把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何元素的称为空栈。栈是一种后进先出的线性表,简称(Last In First Out),简称LIFO结构
二、栈的特性
2.1 地址分布来看:
栈顶地址最低,栈底的地址最高。
2.2栈的特殊之处在于限制了这个线性表的插入与删除位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。
三、栈的应用场景
比如四则运算表达式的求值:
比如我们平常所使用的
9+(3-1)*3 +10/2
这就是我们平时所用的表达式。这里在计算机中可以理解为中缀表达式
在计算机就行运算的时候,它就会将这个运算式变为后缀表达式。也称为逆波兰表达式。
规则:从左至右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分,若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于栈顶符号则栈顶元素依次出栈并输出。
栈的应用–递归
比如我们通常所使用的那些递归函数,其本质就相当于是栈的操作。,比如斐波那契数列,其就是从栈顶到栈底依次出栈。还有链表的逆序打印,其本质也是栈的入栈与出栈操作,先进的反而后走。
在不改变原链表的情况下逆序打印链表
栈的定义
typedef int datatype1;
typedef struct Stack {
datatype1* val1;
int size;
int capacity;
}Stack;
链表的定义
typedef int datatype;
typedef struct list
{
datatype val;
struct list* next;
}Node;
typedef Node* LinkNode;
栈的初始化
void init1(Stack* s)
{
assert(s);
s->val1 = (datatype1*)malloc(sizeof(datatype1) * 5);
s->capacity = 5;
s->size = 0;
}
链表的初始化,这个链表是带头结点的,方便操作
LinkNode init()
{
LinkNode pheader = (LinkNode)malloc(sizeof(Node));
pheader->val = -1;
pheader->next = NULL;
return pheader;
}
栈的扩容
void extend(Stack* s)
{
if (s->size == s->capacity)
{
s->val1 = (datatype1*)realloc(s->val1, sizeof(datatype1) * s->capacity * 2);
if (s->val1 == NULL)
{
printf("内存扩容失败\n");
return;
}
s->capacity *= 2;
}
}
链表内存开辟
LinkNode my_malloc(datatype val)
{
LinkNode newnode = (LinkNode)malloc(sizeof(Node));
newnode->next = NULL;
newnode->val = val;
return newnode;
}
链表的插入,默认的是头插,因为简单才这么插入
void insert(LinkNode pheader, datatype val)
{
if (pheader == NULL)
{
return;
}
LinkNode newnode = my_malloc(val);
newnode->next = pheader->next;
pheader->next = newnode;
}
入栈操作
void pushStack(Stack* s, datatype1 num)
{
assert(s);
extend(s);
s->val1[s->size++] = num;
}
出栈操作
void popStack(Stack* s)
{
if (is_empty(s))
{
return;
}
else
{
s->size--;
}
}
利用递归实现链表逆序打印
void show_bydigit(LinkNode pheader)参数传递是show_bydigit(pheader->next)
{
/*if (pheader)
{
show(pheader->next);
printf("%d\n", pheader->val);
}
}
利用栈来实现,首先执行入栈操作,将链表有效元素依次压入栈中
void show(LinkNode pheader,Stack *s)
{
//这块是让pheader不为空的情况下,先让它入栈,最后再执行出栈,出栈会在后面给出
while (pheader)
{
pushStack(s, pheader->val);
pheader = pheader->next;
}
}
栈的判空操作:
bool is_empty(Stack* s)
{
assert(s);
if (s->size != 0)
{
return false;
}
return true;
}
利用栈来实现逆序打印操作
void stack_show(Stack* s)
{
//因为在上面已经给出了入栈操作,我们这时可以利用栈的特性先进后出来实现逆序打印
while (!<