C语言单链队列的表示与实现实例详解

C语言单链队列的表示与实现实例详解

什么是队列?

在计算机科学中,队列(Queue)是一种特殊的数据结构,它只允许在一端进行插入操作,在另一端进行删除操作。将新元素插入队列的过程可以称之为入队,而将元素从队列中删除的过程则可以称之为出队。队列的核心思想是“先进先出”(First In First Out,FIFO),即先入队的元素先出队。

单链队列的表示方式

单链队列(Linked Queue)是一种基于链表的队列实现方式,它由若干个结点构成,每个结点至少需要包含两个部分:数据域和指针域。数据域用于存储实际数据,指针域则用于指向下一个结点。在单链队列中,队首指针指向链表头结点,队尾指针则指向链表尾结点。

单链队列的基本操作包括以下几个方面:

  • 初始化队列
  • 判断队列是否为空
  • 获取队列长度
  • 入队操作
  • 出队操作
  • 清空队列
  • 销毁队列

下面根据C语言代码实现这些操作。

单链队列的初始化操作

typedef struct QueueNode {
    int data;   // 数据域
    struct QueueNode *next;  // 指针域
} QueueNode, *QueueNodePtr;

typedef struct {
    QueueNodePtr front; // 队首指针
    QueueNodePtr rear;  // 队尾指针
    int length;     // 队列长度
} LinkedQueue;

// 初始化队列
void initQueue(LinkedQueue *queue) {
    queue->front = queue->rear = (QueueNodePtr) malloc(sizeof(QueueNode));
    if (NULL == queue->front) {
        exit(1);    // 内存分配失败,退出程序
    }
    queue->front->next = NULL;  // 队列为空,指向空指针
    queue->length = 0;
}

在队列初始化时,我们需要分配一个头结点,同时将队首和队尾指针都指向这个头结点,表示队列空。由于初始化操作有可能分配失败,因此需要进行内存异常处理。

单链队列的入队操作

// 入队操作
void enQueue(LinkedQueue *queue, int data) {
    QueueNodePtr p;
    p = (QueueNodePtr) malloc(sizeof(QueueNode));
    if (NULL == p) {
        exit(1);    // 内存分配失败,退出程序
    }
    p->data = data;
    p->next = NULL;
    queue->rear->next = p;
    queue->rear = p;
    queue->length++;
}

在入队操作中,我们需要新建一个结点,为其赋值后再插入到队列的尾部。为此需要指针操作,将尾指针指向新结点即可。同时还需要维护队列长度变量。

单链队列的出队操作

// 出队操作
int deQueue(LinkedQueue *queue) {
    int data;
    QueueNodePtr p;
    if (queue->front == queue->rear) {
        printf("队列为空\n");
        exit(1);
    }
    p = queue->front->next;
    data = p->data;
    queue->front->next = p->next;   // 将头结点的指针指向下一个结点
    if (queue->rear == p) {     // 最后一个结点出队,需要更新队尾指针
        queue->rear = queue->front;
    }
    free(p);
    queue->length--;
    return data;
}

在出队操作中,我们需要先判断队列是否为空。如果不为空,我们需要获取队列头结点的下一个结点,并将头结点的指针指向这个结点即可。如果出队的是队列中唯一的结点,则需要同时更新队首和队尾指针。

示例1:用单链队列求解斐波那契数列

下面我们来看一个具体的示例,在这个例子中,我们将使用单链队列来求解斐波那契数列。

斐波那契数列是指这样一个数列:0、1、1、2、3、5、8、13、21、34、…… 它从第三项开始,每一项都等于前两项之和,即 f(n) = f(n-1) + f(n-2)。用数学公式来表示,就是:

f(0) = 0
f(1) = 1
f(n) = f(n-1) + f(n-2) , n>=2

我们可以定义一个单链队列来保存前两个数,然后循环计算下一个数,并将其加入到队列中,直至计算出需要的数。

以下是用单链队列求解斐波那契数列的C语言代码:

// 用单链队列求解斐波那契数列
void fibonacciByLinkedQueue(int n) {
    LinkedQueue queue;
    initQueue(&queue);
    enQueue(&queue, 0);
    enQueue(&queue, 1);

    for (int i = 0; i < n; i++) {
        int x = deQueue(&queue);
        int y = deQueue(&queue);
        printf("%d ", x);
        enQueue(&queue, y);
        enQueue(&queue, x+y);
    }
    printf("\n");
    clearQueue(&queue);
}

这个例子中,我们需要初始化一个队列,并将前两个斐波那契数列中的值入队。然后在循环中计算下一个数,同时将新计算出来的数加入到队列中即可。

示例2:用单链队列解决迷宫问题

下面我们来看另一个例子,它展示了单链队列在解决迷宫问题时的应用。

在迷宫问题中,我们需要遍历迷宫的所有路径,并找到从起点到终点的一条路径。这个过程可以使用深度优先搜索算法来实现。当然,我们也可以使用广度优先搜索算法来解决这个问题。

广度优先搜索算法使用队列来进行遍历,具体实现方式是:先将起点入队,然后每次出队一个节点,检查它的邻居是否可以到达终点,如果可以就入队,如果不行就弹出继续遍历下一个节点,直至遇到终点。

以下是用单链队列解决迷宫问题的C语言代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ROW 8
#define COL 8

typedef struct Point {
    int x;
    int y;
} Point;

// 定义迷宫的矩阵
int map[ROW][COL] = {
    {0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 0, 1, 1, 1, 0},
    {0, 1, 1, 0, 1, 1, 1, 0},
    {0, 1, 1, 1, 1, 0, 0, 1},
    {0, 1, 0, 0, 0, 1, 1, 1},
    {0, 1, 1, 1, 0, 1, 1, 1},
    {0, 1, 0, 1, 1, 1, 0, 0},
    {0, 1, 1, 1, 0, 1, 1, 0}
};

// 定义单链队列的结构体
typedef struct QueueNode {
    Point data;
    struct QueueNode *next;
} QueueNode, *QueueNodePtr;

typedef struct {
    QueueNodePtr front;
    QueueNodePtr rear;
    int length;
} LinkedQueue;

// 初始化队列
void initQueue(LinkedQueue *queue) {
    queue->front = queue->rear = (QueueNodePtr) malloc(sizeof(QueueNode));
    if (NULL == queue->front) {
        exit(1);
    }
    queue->front->next = NULL;
    queue->length = 0;
}

// 入队操作
void enQueue(LinkedQueue *queue, Point data) {
    QueueNodePtr p;
    p = (QueueNodePtr) malloc(sizeof(QueueNode));
    if (NULL == p) {
        exit(1);
    }
    p->data = data;
    p->next = NULL;
    queue->rear->next = p;
    queue->rear = p;
    queue->length++;
}

// 出队操作
Point deQueue(LinkedQueue *queue) {
    Point data;
    QueueNodePtr p;
    if (queue->length == 0) {
        printf("队列为空\n");
        exit(1);
    }
    p = queue->front->next;
    data = p->data;
    queue->front->next = p->next;
    if (queue->rear == p) {
        queue->rear = queue->front;
    }
    free(p);
    queue->length--;
    return data;
}

// 判断是否越界
int isOutOfBounds(int x, int y) {
    if (x < 0 || x >= ROW || y < 0 || y >= COL) {
        return 1;
    }
    return 0;
}

// 判断当前点是否为终点
int isEndpoint(Point point) {
    return point.x == 6 && point.y == 7;
}

// 判断是否为障碍物
int isObstacle(Point point) {
    return map[point.x][point.y] == 1;
}

// 解决迷宫问题
void mazeSolution() {
    LinkedQueue queue;
    initQueue(&queue);
    Point start = {1, 0};
    Point end = {6, 7};
    enQueue(&queue, start);
    int book[ROW][COL];  // 记录每个点是否被走过
    memset(book, 0, ROW*COL*sizeof(int));  // 初始化为0

    int next[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};   // 右、左、下、上

    while (queue.length > 0) {
        Point current = deQueue(&queue);
        if (isEndpoint(current)) {
            printf("解:%d,%d\n", current.x, current.y);
            int x = current.x;
            int y = current.y;
            while (x != start.x || y != start.y) {
                // 逆推路径
                for (int i = 0; i < 4; i++) {
                    int tx = x - next[i][0];
                    int ty = y - next[i][1];
                    if (!isOutOfBounds(tx, ty) && book[tx][ty] == book[x][y]-1) {
                        printf("解:%d,%d\n", tx, ty);
                        x = tx;
                        y = ty;
                        break;
                    }
                }
            }
            clearQueue(&queue);
            return;
        }

        for (int i = 0; i < 4; i++) {
            int nx = current.x + next[i][0];
            int ny = current.y + next[i][1];
            Point nextPoint = {nx, ny};
            if (!isOutOfBounds(nx, ny) && !isObstacle(nextPoint) && book[nx][ny] == 0) {
                book[nx][ny] = book[current.x][current.y] + 1;
                enQueue(&queue, nextPoint);
            }
        }
    }

    printf("无解\n");
    clearQueue(&queue);
}

int main() {
    mazeSolution();
    return 0;
}

这个例子中,我们使用单链队列来实现广度优先搜索算法,求解迷宫问题。其中需要用到元素类型为Point的队列,因此需要在队列中进行相应的修改。通过遍历矩阵中的每个点,我们可以找到从起点到终点的一条路径。在遍历过程中,我们需要注意的是先入队后出队,同时在每个点上将路径距离的长度记录下来,以便之后回推路径。

以上代码可能有些长,但只要代码实现细节都注意到位,就可以很好地解决相关问题。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言单链队列的表示与实现实例详解 - Python技术站

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

相关文章

  • java数据结构基础:算法

    Java数据结构基础:算法攻略 概述 在程序员的日常开发中,算法是一项重要的技能,而数据结构则是算法不可缺少的基础。本文将讲解Java数据结构中的基本算法,包括常见算法的实现,算法的分析及算法的运用。经过本文的学习,读者可以掌握Java中基础的算法实现及应用。 常见算法实现 排序算法 排序算法是算法中最基础的一类,常用的算法有冒泡排序、插入排序、选择排序、快…

    数据结构 2023年5月17日
    00
  • 浅谈iOS 数据结构之链表

    浅谈iOS 数据结构之链表 在计算机科学中,链表是一种数据结构,用于存储一系列按顺序排列的元素。链表的一个关键点是它不需要连续的内存空间来存储元素,相反,每个元素由一个指向下一个元素的指针组成。在iOS开发中,链表在各种场景下都有所应用,如UITableView和UICollectionView的数据源等。本文将详细讲解链表的基本知识和使用技巧。 链表的基本…

    数据结构 2023年5月17日
    00
  • 多维度深入分析Redis的5种基本数据结构

    多维度深入分析Redis的5种基本数据结构 Redis是一种高性能、内存数据存储系统,它支持多种数据结构,包括字符串、哈希表、列表、集合和有序集合。其中,每种数据结构都具有不同的特性和用途,本文将对这五种基本数据结构进行深入分析。 1. 字符串(string) 字符串是最基本的数据结构,一个字符串可以存储任意二进制数据,例如一个jpg图片或者一个序列化的对象…

    数据结构 2023年5月17日
    00
  • Java面试题冲刺第十九天–数据库(4)

    本篇攻略是针对Java数据库相关面试题的,为了方便浏览,我将其分为以下几个部分: 1. 数据库连接池 在Java开发中,我们使用JDBC连接数据库进行数据操作时,为了提高数据库访问性能,通常会使用数据库连接池技术。常见的数据库连接池有:C3P0、Druid、HikariCP等。 C3P0 C3P0是一个开源的数据库连接池,可以设置最大连接数、最小连接数、最大…

    数据结构 2023年5月17日
    00
  • C++数据结构链表基本操作示例过程

    C++数据结构链表基本操作示例过程 链表是一种重要的数据结构,C++中链表的操作是非常常见的,下面我将详细介绍C++中链表的基本操作,包括创建链表、插入节点、删除节点和遍历链表等。 创建链表 首先,需要创建一个链表结构体,并定义节点类型struct Node,其中包含元素数据及下一个节点的指针。 struct Node { int data; Node* n…

    数据结构 2023年5月17日
    00
  • C语言详解数据结构与算法中枚举和模拟及排序

    我们一步步来详细讲解“C语言详解数据结构与算法中枚举和模拟及排序”的完整攻略。 纲要 本文的主要内容包括: 枚举的概念及应用 模拟的概念及应用 排序的概念及分类 枚举的概念及应用 枚举是一种数据类型,可以将一组具有相关性质的常量定义为枚举常量。枚举常量默认是按照自然数递增的顺序进行编号的。枚举常量可以用于表示状态、类型、结果等概念。以下是一个枚举类型的定义:…

    数据结构 2023年5月17日
    00
  • 【牛客小白月赛70】A-F题解【小d和超级泡泡堂】【小d和孤独的区间】【小d的博弈】【小d和送外卖】

    比赛传送门:https://ac.nowcoder.com/acm/contest/53366 难度适中。 ? 作者:Eriktse? 简介:19岁,211计算机在读,现役ACM银牌选手?力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)?? 阅读原文获得更好阅读体验:https://www.erikt…

    算法与数据结构 2023年4月17日
    00
  • C语言数据结构与算法之排序总结(二)

    C语言数据结构与算法之排序总结(二) 本篇文章是关于C语言数据结构与算法中排序算法的详细讲解,涉及了八种排序算法。 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法。在排序过程中,它会重复地交换相邻的元素,这是它名称的由来。 示例代码: c void bubble_sort(int arr[], int n) { for (int i = 0…

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