栈
在线性逻辑结构中,可以是顺序存储和链式存储两种方式,其操作可以在线性表中的任意位置实现,可能不符合实际应用需求。优化的线性表,其中包含栈和队列
(注意:一下代码均以C语言实现)
1 栈的概述
所谓的栈,也称为堆栈,是一个特殊的线性逻辑关系。只能在固定端实现栈的读写访问,其固定端称为栈顶,与之对应的另外一端称为栈底(不参与数据运算)。
栈操作特点:先进后出、后进先出;
栈的存储结构:
顺序存储结构:是一个特殊的顺序表,在连续存储空间中顺序存储,通过数据元素存储位置序号表示数据元素之间的逻辑结构关系。
链式存储结构;是一个特殊的链表,在非连续存储空间中存储数据元素,通过指针表示数据元素逻辑结构关系。
2 顺序栈
2.1 顺序栈的操作
2.1.1 顺序栈数据类型的定义
/* 栈数据元素数据类型的定义 */
typedef int data_t;
/* 动态栈数据类型的定义 */
typedef struct sqstack {
data_t *data; /* 连续存储空间起始地址 */
int nmemb; /* 顺序栈可存储数据元素个数 */
int top; /* 栈顶元素存储位置序号 */
} sqstack_t ;
2.1.2 创建顺序栈
sqstack_t *CreateSqStack(int mynmemb)
{
sqstack_t *stack;
/* 动态创建栈信息存储结构体空间 */
stack = malloc(sizeof(sqstack_t));
if (stack == NULL)
return NULL;
memset(stack, 0, sizeof(sqstack_t));
/* 动态创建顺序栈数据元素存储空间 */
stack->data = calloc(mynmemb, sizeof(data_t));
if (stack->data == NULL) {
free(stack);
return NULL;
}
stack->nmemb = mynmemb;
stack->top = -1;
return NULL;
}
2.1.3 入栈
所谓的栈,也就是栈顶插入数据。
int PushSqStack(sqstack_t *stack, data_t mydata)
{
if (stack == NULL)
return -1;
/* 判断栈空间是否为满,满则入栈失败*/
if (stack->top == stack->nmemb-1)
return -1;
/* 入栈 */
stack->data[++stack->top] = mydata;
return 0;
}
2.1.4 出栈
/* 出栈 */
int PopSqStack(sqstack_t *stack)
{
if (stack == NULL)
return -1;
/* 判断栈空间是否为空 */
if (stack->top == -1)
return -1;
stack->top--; /* 出栈操作 */
return 0;
}
2.1.5 查看栈顶元素
/* 查看栈顶元素数据 */
int GetSqStack(sqstack_t *stack, data_t *mydata)
{
if (stack == NULL)
return -1;
/* 判断栈空间是否为空 */
if (stack->top == -1)
return -1;
*mydata = stack->data[stack->top];
return 0;
}
2.1.6 其它操作
/* 清空栈 */
void ClearSqStack(sqstack_t *stack)
{
if (stack == NULL)
return;
stack->top = -1;
}
/* 释放栈空间 */
void DestorySqStack(sqstack_t **stack)
{
free((*stack)->data);
free(*stack);
*stack = NULL;
}
2.2 顺序栈分类
顺序栈数据元素存储空间,为连续存储空间,在连续存储空间中,
-
可以根据栈的地址生长空间分为递增栈和递减栈
所谓的递增栈,指的是堆栈的地址是由低地址向高地址方向生长;
所谓的递减栈,指的是堆栈的地址是由高地址向低地址方向生长。
-
可以根据栈顶指针(栈顶序号位置)数据是否有效分为满栈和空栈
所谓的满栈,指的是栈顶序号位置的数据值为有效数据值;
入栈,先修改栈顶位置,在写入值;出栈,先读取数据值,在修改栈顶位置;
所谓的空栈,指的是栈顶序号位置的数据值为无效数据值;
入栈,先写入数据值,在修改栈顶位置;出栈,先向栈顶位置,在读取数据值;
3 链式栈
所谓的链式栈,是一个特殊的链表,只能在链表的一端进行操作。将**链表的头结点**作为栈顶指针。
队列
1 队列的概述
1.1 队列的概念
所谓的队列,是特殊的线性表;不能在线性表中间位置进行操作,只能在线性表的两端实现操作,此时的两端分别为队头和队尾:
-
队尾(rear):只能实现数据元素的写访问(插入数据元素);
-
对头(front):只能实现数据元素的读访问(查看队头数据元素、取队头数据元素);
队列的特点:先进先出、后进后出。
1.2 队列的存储结构
顺序存储和链式存储两种方式
2 顺序队列
所谓顺序队列,指的是队列的顺序存储结构,此时队列中的数据元素在练习内存空间中存储。
2.1 顺序队列的理解
- 普通的顺序队列
- 顺序循环队列
2.2 顺序队列的操作
2.2.1 顺序循环队列数据类型的定义
/* 数据元素数据类型的定义 */
typedef int data_t;
/* 顺序循环队列 */
typedef struct sqqueue
data_t *data;
int nmemb;
int front; /* 队头游标:存储队头元素序号 */
int rear; /* 队尾游标:存储队尾元素序号 */
} sqqueue_t;
2.2.2 顺序循环队列的创建
sqqueue_t *CreateSqQueue(int mynmemb)
{
sqqueue_t *queue;
/* 动态创建顺序循环队列信息存储结构体空间 */
queue = malloc(sizeof(sqqueue_t));
if (queue == NULL)
return NULL;
/* 动态开辟顺序循环队列数据元素存储空间 */
queue->data = calloc(mynmemb, sizeof(data_t));
if (queue->data == NULL) {
free(queue);
return NULL;
}
queue->nmemeb = mynmemb;
queue->front = 0;
queue->rear = 0;
return queue;
}
2.2.3 顺序队列操作实现
/* 入队 */
int EnSqQueue(sqqueue_t *queue, data_t mydata)
{
if (queue == NULL)
return -1;
/* 判断队列是否为满队列 */
if ((queue->rear - queue->front) % queue->nmemb == queue->nmemb -1)
return -1;
queue->data[queue->rear] = mydata;
queue->rear = (queue->rear+1) % queue->nmemb;
return 0;
}
/* 出队 */
int DeSqQueue(sqqueue_t *queue)
{
if (queue == NULL)
return -1;
/* 判断队列是否为空队列 */
if (queue->rear == queue->front)
return -1;
/* 出队运算 */
queue->front = (queue->front+1) % queue->nmemb;
return 0;
}
/* 查看队头数据元素 */
int GetSqQueue(sqqueue_t *queue, data_t *mydata)
{
if (queue == NULL)
return -1;
/* 判断队列是否为空队列 */
if (queue->rear == queue->front)
return -1;
*mydata = queue->data[queue->front];
return 0;
}
/* 判断队列是否为空 */
int isEmptySqQueue(sqqueue_t *queue)
{
return (queue->rear == queue->front);
}
/* 判断队列是否为空 */
int isFillSqQueue(sqqueue_t *queue)
{
return ((queue->rear - queue->front) % queue->nmemb == queue->nmemb -1);
}
/* 清空队列 */
void ClearSqQueue(sqqueue_t *queue)
{
queue->front = queue->rear = 0;
}
/* 销毁队列 */
void DestorySqQueue(sqqueue_t **queue)
{
free((*queue)->data);
free(*queue);
*queue = NULL;
}
3 链式队列
所谓的链式队列,表示为队列的链式存储结构,是特殊的链表。只能在链表的两端进行访问,其中一端(链表头部)进行数据的读操作(读取队头数据元素的数据、出队操作),另外一端(链表尾部)进行数据的写操作(入队操作)。
3.1 链式队列数据类型的定义
/* 链式队列中结点数据域的数据类型定义 */
typedef int data_t;
/* 链式队列中结点是数据类型定义 */
typedef struct node {
data_t data; /* 数据域 */
struct node *next; /* 指针域 */
} node_t;
/* 链式队列数据类型 */
typedef struct linkqueue {
node_t * front; /* 队头指针 */
node_t * rear; /* 队尾指针 */
} linkqueue_t;
3.2 链式队列的创建(初始化)
linkqueue_t *CreateLinkQueue(void)
{
linkqueue_t *queue;
/* 动态创建链式队列队头指针和队尾指针存储空间 */
queue = malloc(sizeof(linkqueue_t));
if (queue == NULL)
return NULL;
/* 创建无效数据结点,作为队头指针结点 */
queue->front = malloc(sizeof(node_t));
if (queue->front == NULL) {
free(queue);
return NULL;
}
queue->front->next = NULL;
queue->rear = queue->front; /* 空队列 */
return queue;
}
3.3 链式队列的操作
/* 入队操作 */
int EnLinkQueue(linkqueue_t *queue, data_t mydata)
{
node_t *q;
/* 判断链式队列是否存在 */
if(queue == NULL)
return -1;
/* 判断链式队列尾部结点是否存在 */
if(queue->rear == NULL)
return -1;
/* 创建插入数据结点 */
q = malloc(sizeof(node_t));
if (q == NULL)
return -1;
memset(q, 0, sizeof(node_t));
q->data = mydata; /* 结点数据初始化 */
q->next = NULL;
queue->rear->next = q; /* 插入结点:链表尾部结点后插入结点 */
queue->rear = q; /* 修改队尾指针 */
return 0;
}
/* 读取队头结点数据 */
int GetLinkQueue(linkqueue_t *queue, data_t *mydata)
{
/* 判断链式队列是否存在 */
if(queue == NULL)
return -1;
/* 判断链式队列头部结点是否存在 */
if(queue->front == NULL)
return -1;
/* 判断链式队列是否为空队列 */
if (queue->front->next == NULL)
return -1;
*mydata = queue->front->next->data;
return 0;
}
int DeLinkQueue(linkqueue_t *queue)
{
node_t *q;
/* 判断链式队列是否存在 */
if(queue == NULL)
return -1;
/* 判断链式队列头部结点是否存在 */
if(queue->front == NULL)
return -1;
/* 判断链式队列是否为空队列 */
if (queue->front->next == NULL)
return -1;
/* 出队操作 */
q = queue->front->next;
queue->front->next = q->next;
free(q);
if(queue->front->next == NULL)
queue->rear = queue->front;
return 0;
}
4 练习
- 如何使用两个队列实现一个栈
void push(linkqueue_t *queue_a, linkqueue_t *queue_b, data_t mydata)
{
if (isEmptyLinkQueue(queue_a)) {
EnLinkQueue(queue_b, mydata);
} else {
EnLinkQueue(queue_a, mydata);
}
}
int pop(linkqueue_t *queue_a, linkqueue_t *queue_b, data_t *mydata)
{
if (isEmptyLinkQueue(queue_a)) {
if (isEmptyLinkQueue(queue_b)) {
return -1; /* 没有数据可以出栈 */
}
while(1) {
if (GetLinkQueue(queue_b, mydata) == -1)
return -1;
DeLinkQueue(queue_b);
if (isEmptyLinkQueue(queue_b)) {
return 0;
}
EnLinkQueue(queue_a, *mydata);
}
} else {
while(1) {
if (GetLinkQueue(queue_a, mydata) == -1)
return -1;
DeLinkQueue(queue_a);
if (isEmptyLinkQueue(queue_a)) {
return 0;
}
EnLinkQueue(queue_b, *mydata);
}
}
}
int main()
{
data_t mydata;
linkqueue_t *queue_a;
linkqueue_t *queue_b;
queue_a = CreateLinkQueue();
if (queue_a == NULL)
return -1;
queue_b = CreateLinkQueue();
if (queue_b == NULL)
return -1;
mydata = 5;
while(mydata) {
printf("push data : %d\n", mydata);
push(queue_a, queue_b, mydata); /* 数据元素的入栈先后顺序为:5 4 3 2 1 */
mydata--;
}
printf("-----------%d------------\n", __LINE__);
while(1) {
if (pop(queue_a, queue_b, &mydata) == -1) /* 数据元素的出栈先后顺序:1 2 3 4 5 */
break;
printf("pop data : %d\n", mydata);
}
}
- 如何使用两个栈实现一个队列
int DeQueue(node_t * top_a, node_t * top_b, data_t *mydata)
{
if (top_b->next == NULL) {
while(1) {
if (GetLinkStack(top_a, mydata) == -1)
break;
PopLinkStack(top_a);
PushLinkStack(top_b, *mydata);
}
}
if (top_b->next == NULL)
return -1;
GetLinkStack(top_b, mydata);
PopLinkStack(top_b);
return 0;
}
int EnQueue(node_t * top_a, node_t * top_b, data_t mydata)
{
PushLinkStack(top_a, mydata);
}
int main()
{
node_t * top_a;
node_t * top_b;
data_t mydata;
top_a = CreateLinkStack();
if (top_b == NULL)
return -1;
top_b = CreateLinkStack();
if (top_b == NULL)
return -1;
mydata = 5;
while(mydata) {
printf("%d push is %d\n", mydata--, EnQueue(top_a, top_b, mydata));
}
while(1) {
if (-1 == DeQueue(top_a, top_b, &mydata))
break;
printf("mydata = %d\n", mydata);
}
}
标签:return,队列,queue,概念,mydata,相关,NULL,data
From: https://blog.csdn.net/weixin_65477256/article/details/140798280