数据结构入门:栈和队列

一、栈的基本概念

栈是一种特殊的线性表,其操作限制在固定的一端(栈顶)。这种结构遵循后进先出(LIFO)原则,常见于堆叠的盘子、函数调用等场景。关键术语包括:

  • 栈顶:允许插入和删除的一端。
  • 栈底:栈顶的对端。
  • 入栈(push):向栈顶插入元素。
  • 出栈(pop):从栈顶移除元素。
  • 取栈顶(top):获取栈顶元素但不移除。

栈的存储形式

栈的实现可分为顺序栈和链式栈:

顺序栈

通过数组实现,需预先分配连续内存空间。结构体定义如下:

typedef struct {
    datatype *data;  // 存储数组
    int size;        // 栈容量
    int top;         // 栈顶下标(初始为-1)
} seqStack;

链式栈

通过链表实现,动态分配节点内存。结构体定义如下:

typedef struct node {
    datatype data;
    struct node *next;
} node;

typedef struct {
    node *top;  // 栈顶指针
    int size;   // 元素个数
} linkStack;

基本操作实现

顺序栈操作
// 初始化栈
seqStack *initStack(int size) {
    seqStack *s = malloc(sizeof(seqStack));
    if (s) {
        s->data = malloc(sizeof(datatype) * size);
        s->size = size;
        s->top = -1;
    }
    return s;
}

// 入栈
bool push(seqStack *s, datatype data) {
    if (s->top == s->size - 1) return false;
    s->data[++s->top] = data;
    return true;
}

// 出栈
bool pop(seqStack *s, datatype *pm) {
    if (s->top == -1) return false;
    *pm = s->data[s->top--];
    return true;
}

链式栈操作
// 初始化栈
linkStack *initStack() {
    linkStack *s = malloc(sizeof(linkStack));
    if (s) {
        s->top = NULL;
        s->size = 0;
    }
    return s;
}

// 入栈
bool push(linkStack *s, datatype data) {
    node *newNode = malloc(sizeof(node));
    if (!newNode) return false;
    newNode->data = data;
    newNode->next = s->top;
    s->top = newNode;
    s->size++;
    return true;
}

// 出栈
bool pop(linkStack *s, datatype *pm) {
    if (!s->top) return false;
    node *tmp = s->top;
    *pm = tmp->data;
    s->top = tmp->next;
    free(tmp);
    s->size--;
    return true;
}

关键区别

  • 顺序栈:内存连续,容量固定,适合已知最大规模的场景。
  • 链式栈:动态扩容,内存分散,适合规模不确定的场景。

应用场景

  • 函数调用栈
  • 表达式求值(如括号匹配)
  • 浏览器历史记录(后退功能)

二、队列的基本概念

队列是一种特殊的线性表,遵循先进先出(FIFO)原则。只能在固定两端操作:

  • 队头:删除节点的一端
  • 队尾:插入节点的一端
  • 入队(enQueue()):在队尾插入节点
  • 出队(outQueue()):从队头删除节点
  • 取队头(front()):获取队头元素但不删除

循环队列(顺序存储)

循环队列通过顺序存储实现,利用数组的循环利用特性避免数据移动。需牺牲一个存储单元区分空队和满队:

  • 空队条件:front == rear
  • 满队条件:(rear + 1) % capacity == front

管理结构体示例

struct seqQueue {
    datatype *data;  // 数组入口
    int capacity;     // 总容量
    int front;        // 队头下标
    int rear;         // 队尾下标
};

核心操作代码

// 初始化
seqQueue* initQueue(int cap) {
    seqQueue *q = malloc(sizeof(seqQueue));
    q->data = malloc(cap * sizeof(datatype));
    q->capacity = cap;
    q->front = q->rear = 0;
    return q;
}

// 入队
bool enQueue(seqQueue *q, datatype val) {
    if ((q->rear + 1) % q->capacity == q->front) 
        return false;
    q->data[q->rear] = val;
    q->rear = (q->rear + 1) % q->capacity;
    return true;
}

// 出队
bool outQueue(seqQueue *q, datatype *val) {
    if (q->front == q->rear) 
        return false;
    *val = q->data[q->front];
    q->front = (q->front + 1) % q->capacity;
    return true;
}

链式队列

链式队列通过链表实现,管理结构体保存队头、队尾指针及元素数量:

结构体定义

typedef struct node {
    datatype data;
    struct node *next;
} node;

typedef struct {
    node *front;  // 队头指针
    node *rear;   // 队尾指针
    int size;     // 元素数量
} linkQueue;

核心操作代码

// 入队
bool enQueue(linkQueue *q, datatype val) {
    node *newNode = malloc(sizeof(node));
    newNode->data = val;
    newNode->next = NULL;
    
    if (q->size == 0) 
        q->front = q->rear = newNode;
    else {
        q->rear->next = newNode;
        q->rear = newNode;
    }
    q->size++;
    return true;
}

// 出队
bool outQueue(linkQueue *q, datatype *val) {
    if (q->size == 0) 
        return false;
    *val = q->front->data;
    node *tmp = q->front;
    q->front = q->front->next;
    free(tmp);
    q->size--;
    if (q->size == 0) 
        q->rear = NULL;
    return true;
}

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值