C语言数据结构之栈和队列的实现及应用

C语言数据结构之栈和队列的实现及应用

什么是栈和队列?

栈是一种具有后进先出(LIFO)特性的线性数据结构,可以理解为一个只能在一端进行插入和删除操作的数据结构。通常称插入元素的一端为栈顶,删除元素的一端为栈底。

队列是一种具有先进先出(FIFO)特性的线性数据结构,可以理解为一个只能在两端进行插入和删除操作的数据结构。一端进行插入操作,称之为队尾,一端进行删除操作,称之为队首。

栈的实现及应用

栈的实现

在C语言中实现栈用数组和链表两种方式。下面我们讨论数组实现方式。

首先需要定义一个数组和一个指针,指针指向栈顶元素。实现push和pop操作时,修改指针位置并操作数组内容即可。

#define MAX_SIZE 1000

typedef struct {
    int a[MAX_SIZE];
    int top;
} Stack;

void push(Stack *s, int x) {
    if(s->top < MAX_SIZE) {
        s->a[s->top++] = x;
    } else {
        printf("Stack overflow!\n");
    }
}

int pop(Stack *s) {
    if(s->top > 0) {
        return s->a[--s->top];
    } else {
        printf("Stack underflow!\n");
        return -1;
    }
}

栈的应用

常见的栈的应用场景有表达式求值、括号匹配、迷宫问题等,下面我们简单介绍两个示例。

示例1:表达式求值

算术表达式通常是用中缀表示,即操作数在中间,操作符在两侧。为了求值表达式,我们通常将中缀表达式转成后缀表达式,然后用栈求值。下面是示例代码:

int getPrior(char op) {
    if(op == '+' || op == '-') {
        return 1;
    }
    if(op == '*' || op == '/') {
        return 2;
    }
    if(op == '(' || op == ')') {
        return 0;
    }
    return -1;
}

int isOp(char c) {
    return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
}

void infix2postfix(char *infix, char *postfix) {
    Stack s;
    s.top = 0;
    int i, j;
    for(i = 0, j = 0; infix[i]; i++) {
        if(!isOp(infix[i])) {
            postfix[j++] = infix[i];
        } else if(infix[i] == ')') {
            while(s.top && s.a[s.top-1] != '(') {
                postfix[j++] = s.a[--s.top];
            }
            if(s.top) {
                s.top--;
            }
        } else {
            while(s.top && getPrior(s.a[s.top-1]) >= getPrior(infix[i])) {
                postfix[j++] = s.a[--s.top];
            }
            s.a[s.top++] = infix[i];
        }
    }
    while(s.top) {
        postfix[j++] = s.a[--s.top];
    }
    postfix[j] = '\0';
}

int postfixEval(char *postfix) {
    Stack s;
    s.top = 0;
    int i, a, b, c;
    for(i = 0; postfix[i]; i++) {
        if(!isOp(postfix[i])) {
            push(&s, postfix[i] - '0');
        } else {
            a = pop(&s);
            b = pop(&s);
            switch(postfix[i]) {
                case '+':
                    c = a + b;
                    break;
                case '-':
                    c = b - a;
                    break;
                case '*':
                    c = a * b;
                    break;
                case '/':
                    c = b / a;
                    break;
            }
            push(&s, c);
        }
    }
    return pop(&s);
}

示例2:括号匹配

括号匹配问题也可以使用栈来解决。我们遍历字符串,并用栈记录左括号,遇到右括号时出栈一个左括号并匹配,如果不匹配直接返回。

int isMatch(char a, char b) {
    return (a == '(' && b == ')') || (a == '[' && b == ']') || (a == '{' && b == '}');
}

int isBalanced(char *s) {
    Stack stk;
    stk.top = 0;
    int i;
    for(i = 0; s[i]; i++) {
        if(s[i] == '(' || s[i] == '[' || s[i] == '{') {
            push(&stk, s[i]);
        } else if(s[i] == ')' || s[i] == ']' || s[i] == '}') {
            if(!stk.top || !isMatch(stk.a[stk.top-1], s[i])) {
                return 0;
            }
            stk.top--;
        }
    }
    return stk.top == 0;
}

队列的实现及应用

队列的实现

在C语言中实现队列用数组和链表两种方式。下面我们讨论数组实现方式。

与栈相似,需要定义一个数组和两个指针,一个指向队头元素,一个指向队尾元素。实现enqueue和dequeue操作时,修改指针位置并操作数组内容即可。

#define MAX_SIZE 1000

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

void enqueue(Queue *q, int x) {
    if(q->rear < MAX_SIZE) {
        q->a[q->rear++] = x;
    } else {
        printf("Queue overflow!\n");
    }
}

int dequeue(Queue *q) {
    if(q->front < q->rear) {
        return q->a[q->front++];
    } else {
        printf("Queue underflow!\n");
        return -1;
    }
}

队列的应用

常见的队列的应用场景有FIFO算法、消息队列、排队系统等,下面我们简单介绍两个示例。

示例1:FIFO算法

FIFO(First In First Out)算法是一种页面置换算法,也称先进先出算法。它选择最早调入内存的页面进行置换。

#define MEM_SIZE 4

int pageFaults(int *references, int n) {
    Queue q;
    q.front = q.rear = 0;
    int mem[MEM_SIZE] = {0};
    int i, j, faults = 0;
    for(i = 0; i < n; i++) {
        int found = 0;
        for(j = 0; j < MEM_SIZE; j++) {
            if(references[i] == mem[j]) {
                found = 1;
                break;
            }
        }
        if(found) {
            // already in memory
        } else if(q.rear < MEM_SIZE) {
            mem[q.rear++] = references[i];
            enqueue(&q, references[i]);
            faults++;
        } else {
            int top = dequeue(&q);
            for(j = 0; j < MEM_SIZE; j++) {
                if(mem[j] == top) {
                    mem[j] = references[i];
                    break;
                }
            }
            enqueue(&q, references[i]);
            faults++;
        }
    }
    return faults;
}

示例2:消息队列

消息队列是一种异步通信机制,常用于进程间通信。一个进程将消息发送到队列,另一个进程从队列中读取消息。

#define MAX_SIZE 1000

typedef struct {
    int queue[MAX_SIZE];
    int front, rear;
    pthread_mutex_t mutex;
    pthread_cond_t notEmpty, notFull;
} MsgQueue;

void initMsgQueue(MsgQueue *q) {
    q->front = q->rear = 0;
    pthread_mutex_init(&q->mutex, NULL);
    pthread_cond_init(&q->notEmpty, NULL);
    pthread_cond_init(&q->notFull, NULL);
}

void sendMsg(MsgQueue *q, int msg) {
    pthread_mutex_lock(&q->mutex);
    while(q->rear - q->front >= MAX_SIZE) {
        pthread_cond_wait(&q->notFull, &q->mutex);
    }
    q->queue[q->rear++ % MAX_SIZE] = msg;
    pthread_mutex_unlock(&q->mutex);
    pthread_cond_signal(&q->notEmpty);
}

int recvMsg(MsgQueue *q) {
    int msg;
    pthread_mutex_lock(&q->mutex);
    while(q->rear <= q->front) {
        pthread_cond_wait(&q->notEmpty, &q->mutex);
    }
    msg = q->queue[q->front++ % MAX_SIZE];
    pthread_mutex_unlock(&q->mutex);
    pthread_cond_signal(&q->notFull);
    return msg;
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构之栈和队列的实现及应用 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 数据结构与算法大作业:走迷宫程序(C语言,DFS)(代码以及思路)

    好家伙,写大作业,本篇为代码的思路讲解   1.大作业要求 走迷宫程序 问题描述: 以一个 m * n 的长方阵表示迷宫, 0和1分别表示迷宫的通路和障碍。 设计一个程序, 对任意设定的迷宫, 求出一条从入口到出口的通路, 或得出没有通路的结论。 基本要求: (1) 实现一个以链表做存储的栈类型, 然后编写一个求解迷宫的非递归程序。 求的通路以三元组(i, …

    算法与数据结构 2023年5月9日
    00
  • Redis中5种数据结构的使用场景介绍

    下面是详细的攻略: Redis中5种数据结构的使用场景介绍 Redis是一个高性能的无类型的键值数据库,支持多种数据结构。在使用Redis时,了解各种数据结构的使用场景,可以帮助我们更好地使用Redis。 1. String String是Redis最基本的数据结构,可以存储字符串、整数和浮点数,最大长度为512MB。 使用场景: 存储单个值,如用户ID、用…

    数据结构 2023年5月17日
    00
  • Java数据结构学习之栈和队列

    Java数据结构学习之栈和队列 什么是栈 栈(stack)是一种线性数据结构,它只能在一端进行插入和删除操作,这一端被称作栈顶(top)。栈的特点是先进后出(FILO,First-In-Last-Out),即最后进入的元素最先被删除。 栈的实现方式 栈可以使用数组或链表来实现。使用数组实现的栈称作顺序栈,使用链表实现的栈称作链式栈。以下是顺序栈的 Java …

    数据结构 2023年5月17日
    00
  • C语言近万字为你讲透树与二叉树

    C语言近万字为你讲透树与二叉树 什么是树? 树是一种用来组织数据的非线性数据结构,它由一个根节点和若干个子节点组成,并且每个节点可能有若干个子节点。 什么是二叉树? 二叉树是一种特殊的树,它的每个节点最多只有两个子节点,并且分别称为左子节点和右子节点,左子节点在二叉树中永远排在右子节点的前面。 二叉树的遍历方式 二叉树的遍历方式有三种: 前序遍历(preor…

    数据结构 2023年5月17日
    00
  • Java数据结构学习之二叉树

    Java数据结构学习之二叉树 什么是二叉树 二叉树是一种树形数据结构,他的每个节点最多有两个子节点,分别称为左子节点和右子节点。如果一个节点没有子节点,则成为叶子节点。二叉树具有以下性质: 每个节点最多有两个子节点 左子树和右子树是二叉树 二叉树可以为空 二叉树的遍历 为了遍历一棵树,我们可以采用两种算法: 深度优先遍历 深度优先遍历的思路是:从根节点出发,…

    数据结构 2023年5月17日
    00
  • C语言结构体详细图解分析

    针对C语言结构体详细图解分析的攻略,我来详细讲解一下。 一、什么是结构体? 结构体是C语言中一种自定义数据结构类型,是将不同类型的变量组合在一起的方式,形成了新的数据类型。结构体成员可以是任意类型的数据,包括基本类型、数组、指针、函数等,可以理解为一个包含多个变量的大变量。 二、结构体的定义和使用 定义结构体的方式为: struct name { type1…

    数据结构 2023年5月17日
    00
  • 莫比乌斯反演,欧拉反演学习笔记

    (未更完) 我算法中也就差点数论没学了,这几周卷了,学了一下,分享一下啊。 我会讲得详细一点,关于我不懂得地方,让新手更容易理解。 学习反演有很多定义啥的必须要记的,学的时候容易崩溃,所以希望大家能坚持下来。   第一个定义: $\lfloor x\rfloor$:意思是小于等于 $x$ 的最大整数。 数论分块 学习反演之前,要先学习一些边角料,先来看数论分…

    算法与数据结构 2023年4月17日
    00
  • Java数据结构与算法学习之循环链表

    Java数据结构与算法学习之循环链表 本文将详细介绍Java数据结构中的一种链表类型——循环链表,并讲解如何使用Java实现循环链表。同时,本文也提供了两个示例,方便读者更好地理解和运用循环链表。 什么是循环链表 循环链表是一种链表,它与单向链表和双向链表不同之处在于它的最后一个结点指向第一个结点。这就形成了一个循环链,因此称之为循环链表。 如何实现循环链表…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部