数据结构要点总结——05 栈与队列

1.栈

1.1 定义

在之前的学习中,我们知道线性表是具有相同数据类型的n个数据元素的有限序列,而栈就是只允许在一端进行插入和删除操作的线性表。因此栈是一种先进后出(FILO)的结构

1.2 注意事项

        各位老铁,值得注意的是 ,栈的生长方向(从栈底向栈顶)在物理地址大小中,可以是从小到大(栈顶的物理地址大于栈底),也可以是从大到小(栈顶的物理地址小于栈底)。这一点爱出一些选择题!

      在做关于栈的题目时候也需要注意,有的时候 题目会说栈顶指针所指的栈顶是有元素的(左图),有的时候会说栈顶指针指向的是栈顶元素的下一个空间(右图)。不同情况下判断栈空、栈满的条件也不同(比较的物理地址不同)。

       有一种特殊的应用情况,那就是共享栈,在共享栈中,两个栈的栈底分别位于存储空间的两端,向中间增长。这样,两个栈可以共享这一固定大小的存储空间。
 


共享栈的优点包括:
1. 有效地利用了存储空间,尤其在存储空间有限的情况下,避免为两个独立的栈分别分配内存。
2. 降低了内存的开销和分配的复杂性。
 

共享栈也存在一些限制:
 1. 每个栈可用的最大空间受到总空间大小和另一个栈使用情况的限制。
2. 实现和操作相对较复杂,需要特别注意两个栈的增长和边界情况,以避免相互干扰和溢出。

考的话一般只会问判空条件

如果如图的共享栈地址从左向右增长,那么判空条件为top2-top1=1

 

1.3 顺序栈实现

注意这里是顺序栈,各位同学,栈当然也有链式存储,不过因为这种数据结构(线性表、队列、串之类)考研中不咋考察代码,我就懒得写了。

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

#define MAX_SIZE 100

typedef struct {
    int data[MAX_SIZE];
    int top;
}SeqStack;

// 初始化栈
void initStack(SeqStack &stack) {
    stack.top = -1;//注意这里 初始的栈顶指针指向的位置为-1 
}

// 判断栈是否为空
bool isEmpty(SeqStack stack) {
    return stack.top == -1;//判空条件因为初始情况改变 
}

// 判断栈是否已满
bool isFull(SeqStack stack) {
    return stack.top == MAX_SIZE - 1;//判断条件同上 
}

// 入栈
void push(SeqStack &stack, int element) {
    if (isFull(stack)) {
        printf("Stack is full!\n");
        return;
    }
    stack.data[++stack.top] = element;
    //因为初始的时候栈顶指针指向-1,当有元素要进栈时,需要先将top+1到0的位置在入栈
	//可以将这样的情况看作时栈顶指针指向的位置装有元素
	//如果栈顶指针指向位置不装有元素,入栈时可以直接将元素存放在栈顶指针现在所指的位置,而后栈顶指针+1即可(top++) 
}

// 出栈
int pop(SeqStack &stack) {
    if (isEmpty(stack)) {
        printf("Stack is empty!\n");
        return -1;//空了就返回-1 
    }
    int element = stack.data[stack.top];
    stack.top--;
    return element;
}

// 获取栈顶元素
int getTop(SeqStack stack) {//没有&引用,因为只获取不改变栈 
    if (isEmpty(stack)) {
        printf("Stack is empty!\n");
        return -1;
    }
    return stack.data[stack.top];
}

int main() {
    SeqStack stack;
    initStack(stack);

    push(stack, 1);
    push(stack, 2);
    push(stack, 3);
    push(stack, 4);
    push(stack, 5);
    push(stack, 6);

    printf("Top element: %d\n", getTop(stack));//获取栈顶元素 

    int poppedElement = pop(stack);//弹出栈顶元素 
    if (poppedElement!= -1) {//栈没空的情况 
        printf("Popped element: %d\n", poppedElement);
    }

    printf("Top element after pop: %d\n", getTop(stack));//弹出操作之后的栈顶元素 

    return 0;
}
 

2.队列

2.1 定义

什么是队列?队列只允许在一端(常叫队尾)进行插入,另一端(队头)进行删除操作的线性表。这里需要注意,是一边插入,一边删除!!!同时队列是一种先进先出(FIFO)的结构。

2.2 注意事项

各位同学可能会发现,即使是像队列这样可以一头插入,一头删除,依旧不是特别方便,如果可以两头都可以插入删除岂不是太妙了,恭喜你,你发明了双端队列

可是,你还不满足,如果可以在任意限制其中一头的操作那该多方便,比如我想让头部只允许出,但是尾部可以进可以出。那么又得恭喜你了,你发明了操作受限的队列

      和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存 放从队列头到队列尾的元素之外,尚需附设两个指针 front 、 rear 分别指示队列头元素 及队列尾元素的位置。在此我们约定:初始化建空队列 时,令 front= rear= 0 , 每当插入新的队列尾元素时,“尾指针增 1"; 每当删除队列头元素 时,`头指针增1` 因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向 队列尾元素的下一个位置,如图:

然而,当出现(d)这种情况时,在想添加元素就麻烦了,因此如果把头尾连在一起,就可以方便想继续添加元素了,恭喜你发明了循环队列

         此时存在关系式 Q. front=Q. rear, 只凭等式 Q. front= Q. rear 无法 判别队列空间是“空”还是“满”。可有两种处理方法:其一是另设一个标志位以区别队列 是“空”还是“满”;其二是少用一个元素空间,约定以"队列头指针在队列尾指针的下一位 置(指环状的下一位置)上”作为队列呈“满“状态的标志。(自行理解

2.3 队列代码实现(循环队列)

注意看代码的判满!使用的就是少用一个元素空间,约定以"队列头指针在队列尾指针的下一位 置(指环状的下一位置)上”作为队列呈“满“状态的标志,但是会牺牲一个存储空间。

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 6  // 队列的最大容量

typedef struct {
    int data[MAX_SIZE];
    int front;
    int rear;
} Queue;

// 初始化队列
void initQueue(Queue &q) {
    q.front = 0;
    q.rear = 0;
}

// 判断队列是否为空
int isEmpty(Queue q) {
    return q.front == q.rear;
}

// 判断队列是否已满
int isFull(Queue q) {
    return (q.rear + 1) % MAX_SIZE == q.front;//少用一个元素空间,约定以"队列头指针在队列尾指针的下一位置
	//(指环状的下一位置)上”作为队列呈“满“状态的标志。
}

// 入队操作
void enQueue(Queue &q, int element) {
    if (isFull(q)) {
        printf("Queue is full!\n");
        return;
    }
    q.data[q.rear] = element;
    q.rear = (q.rear + 1) % MAX_SIZE;
}

// 出队操作
int deQueue(Queue &q) {
    if (isEmpty(q)) {
        printf("Queue is empty!\n");
        return -1;
    }
    int element = q.data[q.front];
    q.front = (q.front + 1) % MAX_SIZE;
    return element;
}
// 打印队列元素
void printQueue(Queue &q) {
    if (isEmpty(q)) {
        printf("Queue is empty!\n");
        return;
    }
    int i = q.front;
    printf("Queue: ");
    do {
        printf("%d ", q.data[i]);
        i = (i + 1) % MAX_SIZE;
    } while (i!= q.rear);
    printf("\n");
}
int main() {
    Queue q;
    initQueue(q);
    enQueue(q, 10);
    printQueue(q);
    
    enQueue(q, 20);
    printQueue(q);
    
    enQueue(q, 30);
    printQueue(q);
    
    enQueue(q, 40);
    printQueue(q);
    
    enQueue(q, 50);
    printQueue(q);
    
    enQueue(q, 60);
    printQueue(q);
    
    /*int dequeuedElement = deQueue(q);
    if (dequeuedElement!= -1) {
        printf("Dequeued element: %d\n", dequeuedElement);
    }*/
    return 0;
}

如图,60这个元素并没有存入, 在入队的时候显示已经满了,再打印也只有5个元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值