你好,我是史丰源
欢迎你的来访,希望我的博客能给你带来一些帮助。
我的Gitee:代码仓库.☀️
我的联系方式:
QQ:1756786195
邮箱:Marksky126@outlook.com🌐
一、栈的简介(栈不支持遍历)
栈:是一种特殊的线性表,它只允许在一端进行删除和插入(栈顶),插入删除端叫做栈顶,而另一端叫做栈底。
栈中元素遵循 “后进先出” LIFO(Last in first out)原则.
栈的实现
栈可以用数组实现,也可以用链表实现。
这里我们使用数组实现栈
typedef struct Stack//定义一个栈
{
StaType* a;//动态数组地址
int top;//栈顶,相当于顺序表中的size
int capacity;//栈容量
}Stack;
从结构就可知,栈和顺序表的结构极其相似,所以我们可以根据顺序表的操作直接进行编写。
栈的初始化
void StackInit(Stack* ST)
{
assert(ST);
ST->a = NULL;
ST->top = 0;
ST->capacity = 0;
}
栈的销毁(与初始化相比,多了一个释放)
void StackDestory(Stack* ST)
{
assert(ST);
free(ST->a);
ST->a = NULL;
ST->top = 0;
ST->capacity = 0;
}
入栈
void StackPush(Stack* ST, StaType x)
{
assert(ST);
if (ST->top == ST->capacity)//空间满了
{
int newcapacity = ST->capacity == 0 ? 4 : ST->capacity * 2;//新的容量
StaType* tmp = (StaType)realloc(ST->capacity,sizeof(StaType)*newcapacity);//数组扩容
if (tmp == NULL)
{
printf("realloc fail");
exit(-1);
}
ST->a = tmp;
ST->capacity = newcapacity;
}
ST->a[ST->top] = x;//在栈顶插入元素
ST->top++;//栈顶+1
}
栈的判空
bool StackEmpty(Stack* ST)
{
assert(ST);
return ST->top == 0;//如果是0就true,非0-false
//也可自己判断if(ST->top == 0),上面这种结构大大简化代码量
}
出栈
void StackPop(Stack* ST)
{
assert(ST);
assert(!StackEmpty(ST));//栈的判空,如果是空的栈,无法删除,直接报错
ST->top--;//把栈顶指针向下移动一位,移到向下一个结点
}
返回栈顶元素
StaType StackGet_Top(Stack* ST)//返回的是一个数据(元素)
{
assert(ST);
assert(!StackEmpty(ST));
return ST->a[ST->top-1];//top指的是栈顶的下一个位置
//top现在指的位置为空,所以要减一。
}
注意:栈中的元素范围:0~top-1,而出栈和入栈的操作是top的相对增减.
如图:我要出栈7这个元素,第一次top是在7上面的空间,7在top-1的空间,我执行出栈动作:
ST->top--;
7的位置变成top,如果我再插入数据,执行的是入栈操作
ST->a[ST->top] = x;
所以我就把7这个元素给覆盖了
二、队列的简介(队列不支持遍历)
队列:也是一种特殊的顺序表,在队尾插入数据,队头删除数据,遵循 先进先出 FIFO(First in First out)原则。
其适合使用链表进行实现,入队:尾插。出队:头删。
队列实现
队列的定义
typedef int QType;//注意这里写typedef而不是define.
typedef struct QueueNode//结点定义,与单链表实现一致
{
QType data;
struct QueueNode* next;
}QNode;
typedef struct Queue
{
QNode* head;//记录队头结点,记住这里是QNode
QNode* tail;//记录队尾结点
}Queue;
队列的初始化
void InitQueue(Queue* p)
{
assert(p);
p->head = p->tail = NULL;
}
队列的销毁
void DestoryQueue(Queue* p)
{
assert(p);
assert(!QueueEmpty(p));
free(p->head);
free(p->tail);
p->head = p->tail = NULL;
}
入队
void PushQueue(Queue* p, QType x)
{
assert(p);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (p->head == NULL)
{
p->head = p->tail = newnode;//第一次
}
else
{
p->tail->next = newnode;//尾插
p->tail = newnode;
}
}
出队
void PopQueue(Queue* p)//头删呗
{
assert(p);
assert(!QueueEmpty(p));
if (p->head->next == NULL)//只有一个结点
{
free(p->head);
p->head = p->tail = NULL;
}
else
{
QNode* next = p->head->next;
free(p->head);
p->head = next;
}
}
返回队头队尾元素
QType QueueFront(Queue* p)
{
assert(p);
return p->head->data;
}
QType QueueBack(Queue* p)
{
assert(p);
return p->tail->data;
}
队列的长度(也可直接在结构体中定义一个size)
int QueueSize(Queue* p)
{
QNode* cur = p->head;
int size = 0;
while (cur)
{
++size;
cur = cur->next;
}
return size;
}
队列判空
bool QueueEmpty(Queue* p)
{
if (p->head == NULL)
{
return p->head == NULL;
}
}
总结:栈与队列都是特殊的线性表,其结构也与数组与单链表极其相似,我们需记住它们插入与删除的特殊方式,与顺序表加以区分,便可掌握。