数据结构之栈和队列的链式存储结构

250 阅读3分钟

栈的链式存储结构

栈的链式存储结构通常使用单链表来实现,其中链表的头部作为栈顶,尾部作为栈底(尽管在栈的实际操作中我们并不关心栈底)。栈的链式存储结构通常不需要存储栈的最大容量,因为链表可以动态地增长和收缩。

栈的链式存储结构定义(使用C语言):

typedef struct Node {
    int data;
    struct Node *next;
} Node, *Stack;

基本操作:

1、初始化栈:创建一个空节点,并将其地址赋给栈顶指针。

Stack InitStack() {
    Stack S = (Stack)malloc(sizeof(Node));
    if (!S) {
        exit(EXIT_FAILURE);
    }
    S->next = NULL; // 栈顶指向空
    return S;
}

2、判断栈是否为空:如果栈顶指针的下一个节点为空,则栈为空。

int StackEmpty(Stack S) {
    return S->next == NULL;
}

3、入栈:创建一个新节点,将数据放入该节点,然后将新节点插入到栈顶。

void Push(Stack S, int e) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (!newNode) {
        exit(EXIT_FAILURE);
    }
    newNode->data = e;
    newNode->next = S->next; // 新节点指向原栈顶节点
    S->next = newNode; // 更新栈顶指针
}

4、出栈:移除栈顶节点,并释放其内存。

int Pop(Stack S, int *e) {
    if (StackEmpty(S)) {
        return 0; // 出栈失败
    }
    Node *temp = S->next; // 临时保存栈顶节点
    *e = temp->data; // 保存数据
    S->next = temp->next; // 更新栈顶指针
    free(temp); // 释放原栈顶节点内存
    return 1; // 出栈成功
}

5、取栈顶元素:返回栈顶节点的数据,但不移除该节点。

int GetTop(Stack S, int *e) {
    if (StackEmpty(S)) {
        return 0; // 获取失败
    }
    *e = S->next->data;
    return 1; // 获取成功
}

队列的链式存储结构

队列的链式存储结构也使用单链表来实现,但队列需要维护两个指针:一个指向队头(front),另一个指向队尾(rear)。队列的链式存储结构允许队列在两端进行插入和删除操作。

队列的链式存储结构定义(使用C语言):

typedef struct Node {
    int data;
    struct Node *next;
} Node;

typedef struct {
    Node *front; // 队头指针
    Node *rear;  // 队尾指针
} Queue;

基本操作(与栈类似,但队列在队尾插入元素,在队头删除元素):

1、初始化队列:创建两个空指针,分别作为队头和队尾。

Queue InitQueue() {
    Queue Q;
    Q.front = Q.rear = NULL;
    return Q;
}

2、判断队列是否为空:如果队头指针为空,则队列为空。

int QueueEmpty(Queue Q) {
    return Q.front == NULL;
}

3、入队:在队尾插入一个新节点。

void EnQueue(Queue *Q, int e) {
    Node *newNode = (Node*)malloc(sizeof(Node));
    if (!newNode) {
        exit(EXIT_FAILURE);
    }
    newNode->data = e;
    newNode->next = NULL; // 新节点为最后一个节点
    if (QueueEmpty(*Q)) { // 如果队列为空,则新节点同时是队头和队尾
        Q->front = Q->rear = newNode;
    } else { // 否则,新节点成为队尾节点,原队尾节点的next指向新节点
        Q->rear->next = newNode;
        Q->rear = newNode;
    }
}

4、出队:移除队头节点,并释放其内存。

int DeQueue(Queue *Q, int *e) {
    if (QueueEmpty(*Q)) {
        return 0; // 出队失败
    }
    Node *temp = Q->front; // 临时保存队头节点
    *e = temp->data; // 保存数据
    Q->front = temp->next; // 更新队头指针
    if (Q->front == NULL) { // 如果队列为空,队尾指针也为空
        Q->rear = NULL;
    }
    free(temp); // 释放原队头节点内存
    return 1; // 出队成功
}

5、取队头元素:返回队头节点的数据,但不移除该节点。

int GetFront(Queue Q, int *e) {
    if (QueueEmpty(Q)) {
        return 0; // 获取失败
    }
    *e = Q.front->data;
    return 1; // 获取成功
}