数据结构 05 栈和队列

1 栈只在一端(栈顶)进行运算,并非两端

栈是只允许在表的一端(栈顶)进行插入和删除操作的线性表;队列是只允许在表的一端(队尾)进行插入操作,在另一端(队头)进行删除操作的线性表。

所以栈只在一端(栈顶)进行运算,并非两端。

2 循环队列不是以链表指针的方式来实现头尾相接

循环队列的典型实现是基于数组的,通过对数组下标进行特定的运算(如取模)来实现队列的头尾相接,从而重复利用数组空间。

虽然从广义的 "指针" 概念(比如数组下标也可看作一种地址标识),但通常我们所说的用 "指针" 实现,更多是指像链表那样用指针变量来链接节点。

而循环队列一般不用这种链表指针的方式来实现头尾相接,所以这一说法错误,答案选 "×"。

3 队列只允许在一端(队尾)进行插入(增加)操作,在另一端(队头)进行删除(减少)操作

队列是一种 "先进先出"(FIFO)的线性表,只允许在一端(队尾)进行插入(增加)操作,在另一端(队头)进行删除(减少)操作,并非下端和上端既能增加又能减少。

4 当有 n 个元素依次进栈时,合法的出栈序列数目恰好是第 n 个卡特兰数。

5 在单链表表示的链式队列里,队头位于链表的链头位置

队列是 "先进先出" 的线性结构,链式队列中,队头元素是最先进入队列的,在单链表表示的链式队列里,**队头位于链表的链头位置,这样出队(删除队头元素)操作可以直接从链头进行,方便高效;**而队尾位于链尾,用于入队操作。所以用单链表表示的链式队列的队头在链表的链头位置。

6 只有尾指针的循环链队列的入队和出队

以下是用 C 语言实现只有尾指针的循环链队列的入队和出队操作:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 定义队列节点结构
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 入队操作
void enQueue(Node **rear, int value) {
    // 创建新节点
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (newNode == NULL) {
        printf("内存分配失败\n");
        exit(1);
    }
    newNode->data = value;

    // 如果队列为空
    if (*rear == NULL) {
        *rear = newNode;
        newNode->next = newNode; // 自己指向自己,形成循环
    } else {
        // 新节点的 next 指向原队头(尾指针的 next 指向队头)
        newNode->next = (*rear)->next;
        // 尾节点的 next 指向新节点
        (*rear)->next = newNode;
        // 尾指针后移到新节点
        *rear = newNode;
    }
}

// 出队操作
int deQueue(Node **rear) {
    // 队列为空的情况
    if (*rear == NULL) {
        printf("队列为空,无法出队\n");
        exit(1);
    }

    Node *front = (*rear)->next; // 队头节点
    int data = front->data;

    // 如果队列中只有一个节点
    if (front == *rear) {
        *rear = NULL;
    } else {
        // 尾指针的 next 指向原队头的下一个节点,即新的队头
        (*rear)->next = front->next;
    }

    free(front);
    return data;
}

// 测试函数
int main() {
    Node *rear = NULL;

    // 入队
    enQueue(&rear, 1);
    enQueue(&rear, 2);
    enQueue(&rear, 3);

    // 出队并打印
    printf("出队元素: %d\n", deQueue(&rear));
    printf("出队元素: %d\n", deQueue(&rear));
    printf("出队元素: %d\n", deQueue(&rear));

    // 再次入队测试
    enQueue(&rear, 4);
    printf("出队元素: %d\n", deQueue(&rear));

    return 0;
}

代码说明

  1. 入队操作(enQueue
    • 首先创建新节点存储要入队的数据。
    • 如果队列为空(尾指针 rearNULL),则新节点的 next 指向自身,尾指针指向新节点,形成只有一个节点的循环队列。
    • 如果队列不为空,新节点的 next 指向原队头(尾指针的 next 指向队头),然后尾节点的 next 指向新节点,最后尾指针后移到新节点。
  2. 出队操作(deQueue
    • 先判断队列是否为空,为空则无法出队。
    • 找到队头节点(尾指针的 next 指向队头),保存队头节点的数据。
    • 如果队列中只有一个节点,出队后队列为空,尾指针置为 NULL
    • 否则,尾指针的 next 指向原队头的下一个节点(即新的队头),然后释放原队头节点的内存,返回其数据。
  3. 测试部分 :在 main 函数中进行入队和出队操作的测试,验证代码的正确性。

7 实现两个共享存储区、栈顶相向增长的顺序栈的入栈和出栈

1. 定义栈结构

cpp 复制代码
#define maxsize 100 // 假设最大容量为 100
typedef struct {
    int data[maxsize]; // 共享的存储数组
    int top1; // 栈 S1 的栈顶指针,初始为 -1
    int top2; // 栈 S2 的栈顶指针,初始为 maxsize
} DoubleStack;

2. 入栈操作

cpp 复制代码
// 入栈操作,stack 为双栈,x 为入栈元素,stackNum 为栈编号(1 表示 S1,2 表示 S2)
int push(DoubleStack *stack, int x, int stackNum) {
    // 检查是否栈满(两个栈顶指针相邻,说明空间用尽)
    if (stack->top1 + 1 == stack->top2) {
        printf("栈满,无法入栈\n");
        return 0;
    }
    if (stackNum == 1) {
        // S1 入栈,栈顶指针上移,元素放入对应位置
        stack->data[++(stack->top1)] = x;
    } else if (stackNum == 2) {
        // S2 入栈,栈顶指针下移,元素放入对应位置
        stack->data[--(stack->top2)] = x;
    } else {
        printf("栈编号错误\n");
        return 0;
    }
    return 1;
}

3. 出栈操作

cpp 复制代码
// 出栈操作,stack 为双栈,x 用于存储出栈元素,stackNum 为栈编号(1 表示 S1,2 表示 S2)
int pop(DoubleStack *stack, int *x, int stackNum) {
    if (stackNum == 1) {
        // 检查 S1 是否为空
        if (stack->top1 == -1) {
            printf("S1 栈空,无法出栈\n");
            return 0;
        }
        // S1 出栈,栈顶指针下移,取出元素
        *x = stack->data[stack->top1--];
    } else if (stackNum == 2) {
        // 检查 S2 是否为空
        if (stack->top2 == maxsize) {
            printf("S2 栈空,无法出栈\n");
            return 0;
        }
        // S2 出栈,栈顶指针上移,取出元素
        *x = stack->data[stack->top2++];
    } else {
        printf("栈编号错误\n");
        return 0;
    }
    return 1;
}

简单解释

  • 入栈 :两个栈 S1S2 栈顶相向,S1 栈顶从存储区起始位置(top1 初始为 -1)向上增长,S2 栈顶从存储区末尾位置(top2 初始为 maxsize)向下增长。入栈时先判断是否栈满(top1 + 1 == top2 表示空间用尽),若不满则根据栈编号,调整对应栈顶指针并放入元素。
  • 出栈:出栈时先判断对应栈是否为空,若不为空则根据栈编号,调整对应栈顶指针并取出元素。
相关推荐
小此方3 小时前
C语言自定义变量类型结构体理论:从初见到精通(下)
c语言·数据结构·算法
报错小能手3 小时前
linux学习笔记(31)网络编程——TCP time_wait机制
linux·笔记·学习
_poplar_3 小时前
15 【C++11 新特性】统一的列表初始化和变量类型推导
开发语言·数据结构·c++·git·算法
Yupureki3 小时前
从零开始的C++学习生活 7:vector的入门使用
c语言·c++·学习·visual studio
i学长的猫3 小时前
Ruby小白学习路线
开发语言·学习·ruby
送秋三十五4 小时前
Docker 构建教程:学习上下文、架构和性能优化技术
学习·docker·架构
思成不止于此4 小时前
软考中级软件设计师备考指南(四):I/O 技术、安全与可靠性 —— 综合应用篇
网络·笔记·学习·信息安全·总线系统·i/o 技术·可靠性计算
GawynKing4 小时前
红黑树-带源码
数据结构·算法·二叉树··红黑树
聪明的笨猪猪4 小时前
Java Redis “核心应用” 面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试