数据结构与算法总结——队列和栈

3.1 栈

3.1.1 基本概念

栈(Stack)是一种逻辑结构,是特殊的线性表。

  • 只能在固定的一端进行插入或删除的操作的线性表

碗不能从下端抽出

只要满足上述条件,那么这种特殊的线性表就会呈现一种“后进先出”的逻辑,这种逻辑就被称为栈。栈在生活中到处可见,比如堆叠的盘子、电梯中的人们、嵌套函数的参数等等。

由于约定了只能在线性表固定的一端进行操作,于是给栈这种特殊的线性表的“插入”、“删除”,另起了下面这些特定的名称:

  • 栈顶:可以进行插入删除的一端
  • 栈底:栈顶的对端
  • 入栈:将节点插入栈顶之上,也称为压栈,函数名通常为push()
  • 出栈:将节点从栈顶剔除,也称为弹栈,函数名通常为pop()
  • 取栈顶:取得栈顶元素,但不出栈,函数名通常为top()

基于这种固定一端操作的简单约定,栈获得了“后进先出(LIFO)”的基本特性,如下图所示,最后一个放入的元素,最先被拿出来:

3.1.2 栈的存储形式

一般有两种存储方式:

  • 顺序栈
  • 链式栈
3.1.3 栈的基本实现

链式栈的组织形式与链表无异,只不过插入删除被约束在固定的一端。为了便于操作,通常也会创建所谓管理结构体,用来存储栈顶指针、栈元素个数等信息:

定义结构体代码如下:

//栈结点
typedef struct stack{

    int data;//数据域
    struct stack *next;//指针域

}stack;

// 链式栈管理结构体
typedef struct
{
    stack *top; // 链式栈栈顶指针
    int size; // 链式栈当前节点个数
}linkStack;

栈的初始化:构造一个空栈S

//生成管理栈结构体
linkStack *init_linkStack(void)
{
        linkStack *q = (linkStack *)malloc(sizeof(linkStack));
        if(q == NULL)
        {
                printf("malloc fail\n");
                return NULL;
            }
        q->top = NULL;
        q->size = 0;  
        return q;
}



//栈节点初始化
stack *init_stack(int data)
{
        stack *new = (stack *)malloc(sizeof(stack));//结构体指针变量
        if(new == NULL){
            printf("malloc fail\n");
            return NULL;
        }
        new->data = data;
        new->next = NULL;
        //返回开辟节点空间的首地址
        return new;
}

压栈:若栈未满,则将x加入使之成为新栈顶。(增)

//压栈
int push(linkStack *s,stack *new)
{
    if(s->top == NULL){
        s->top = new;
        s->size++;
    }

    else{
        new->next = s->top;
        s->top = new;
        s->size++;
    }
    return 0;
}

出栈:若栈非空,则弹出栈顶元素,并将栈顶元素返回

//出栈,每调用一次,出一个数据
int pop(linkStack *s, int *pdata)
{
       stack *p;
       if(s->size == 0 && s->top == NULL){
           return -1;
       }
       else{
           *pdata = s->top->data;//先存储栈顶地址
           p = s->top;//更新栈顶
           s->top = s->top->next;
           s->size--;
           free(p);//释放节点
           return 0;
       }
}

注意:当栈顶元素被清空后,此时栈为空栈

3.1.4 栈的要点

合法出栈顺序有:

e、d、c、b、a 

b、e、d、c、a

3.2 队列

3.2.1 基本概念

队列(Queue)是只允许在一端进行插入,在另一端删除的线性表,特点是“先进先出(FIFO)

由于约定了只能在线性表固定的两端进行操作,于是给队列这种特殊的线性表的插入删除,起个特殊的名称:

  • 队头:可以删除节点的一端
  • 队尾:可以插入节点的一端
  • 入队:将节点插入到队尾之后
  • 出队:将队头节点从队列中剔除
  • 取队头:取得队头元素,但不出队

出队之后:

动画如下所示:

3.2.2 队列的存储方式

跟平常的线性表一样,分为:

  • 顺序队列
  • 链式队列
3.2.3 队列的实现

定义结构体:

typedef struct queue_node {
    QueueDataType data;
    struct queue_node* next;
} QueueNode;

typedef struct queue {
    QueueNode* front;
    QueueNode* rear;
} Queue;

初始化队列:构造一个空队列。

void initQueue(Queue* q) {
    q->front = q->rear = NULL;
}

判断队列是否为空:

int isEmptyQueue(Queue q) {
    return q.front == NULL;
}

入队:若队列未满,将x加入,使之成为新的队尾。

void enqueue(Queue* q, QueueDataType data) {
    QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
    newNode->data = data;
    newNode->next = NULL;
    if (isEmptyQueue(*q)) {
        q->front = q->rear = newNode;
    } else {
        q->rear->next = newNode;
        q->rear = newNode;
    }
}

出队:若队列非空,删除对头元素,将数据返回。

QueueDataType dequeue(Queue* q) {
    if (isEmptyQueue(*q)) {
        return NULL;
    }
    QueueNode* oldFront = q->front;
    QueueDataType data = oldFront->data;
    q->front = oldFront->next;
    if (q->front == NULL) {
        q->rear = NULL;
    }
    free(oldFront);
    return data;
}

销毁队列:

void clearQueue(Queue* q) {
    while (!isEmptyQueue(*q)) {
        dequeue(q);
    }
}

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值