数据结构7——链式队列

发布于:2025-09-10 ⋅ 阅读:(20) ⋅ 点赞:(0)

前言:
本专栏属于数据结构相关内容,附带一些代码加深对一些内容的理解,为方便读者观看,本专栏内的所有文章会同时附带C语言和Python对应的代码,(可自行通过目录跳转到对应的部分)辅助不同主修语言的读者去更好的理解对应的内容,若是代码0基础的读者,可先去博主其他专栏学习一下基础的语法及知识点:

魔法天才的跳转链接:

C语言:C基础_Gu_shiwww的博客-CSDN博客
Python语言:python1_Gu_shiwww的博客-CSDN博客
其他数据结构内容可见:数据结构_Gu_shiwww的博客-CSDN博客

1 链式队列

        队列在尾部添加元素,在头部删除元素。使用有头单向链表实现队列。那就让链表的头作为队列的头,因为链表头部容易执行删除操作,链表的尾部只能作为队列的尾部,执行插入操作。

        但链表尾部插入操作有一个问题:每次都要遍历整个链表找到终端结点,才能执行插入操作。为了减少遍历,要再维护一个尾指针指向链表的尾部。因此,使用单向链表实现一个队列,链表需要两个指针——头指针和尾指针。头指针指向链表的头部,用于出列。尾指针指向链表尾部,用于入列。

链式栈:无头单向链表,头为栈顶,对无头单向链表进行头插和头删。

链式队列:有头单向链表,头结点为队头,终端结点为队尾,对有头单向链表进行头删和尾插。

1.2 图示

        队列的链式存储结构,其实就是线性表的单链表,只不过它是操作受限的线性表。它只能尾进头出而已,将其简称为链式队列。

        为了操作上的方便,我们将队头指针指向链式队列的头结点,而队尾指针指向终端结点,如下图所示。

入队:

出队:

        思想:释放头节点,然后返回头节点后一个节点的数据从而把它做成新的头节点。所以释放的节点和出数据的节点不是同一个。

2 编程实现链式队列

C语言实现链式队列

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

typedef int datatype;
//链表节点结构体
typedef struct node_t
{
    datatype data;
    struct node_t *next;
} link_node_t, *link_node_p;

//队列结构体:包含头指针和尾指针
typedef struct
{
    link_node_p front;
    link_node_p rear;
} linkqueue_t, *linkqueue_p;

//创建一个空链式队列,用有头链表
linkqueue_p createEmptyLinkQueue()
{
    //1.开辟队列结构体空间
    linkqueue_p p = (linkqueue_p)malloc(sizeof(linkqueue_t));
    if (NULL == p)
    {
        perror("p malloc err");
        return NULL;
    }
    //2.初始化队列结构体空间
    p->front = p->rear = (link_node_p)malloc(sizeof(link_node_t));
    if (NULL == p->front)
    {
        perror("p->front malloc err");
        return NULL;
    }
    //3.对头节点初始化
    p->front->next = NULL;

    return p;
}

//入列 data代表入列的数据
int inLinkQueue(linkqueue_p p, datatype data)
{
    // 新建节点,初始化新节点
    link_node_p pnew = (link_node_p)malloc(sizeof(link_node_t));
    if (NULL == pnew)
    {
        perror("pnew err");
        return -1;
    }
    pnew->data = data;
    pnew->next = NULL;
    // 将尾指针所指节点连接新节点
    p->rear->next = pnew;
    // 移动尾指针到新节点
    p->rear = pnew;

    return 0;
}

//判断队列是否为空
int isEmptyLinkQueue(linkqueue_p p)
{
    return p->front == p->rear;
}

//出列
datatype outLinkQueue(linkqueue_p p)
{
    // 1. 判空:p->rear == p->front;
    if (isEmptyLinkQueue(p))
    {
        perror("out err");
        return -1;
    }
    // 2. 设指针pdel指向要释放节点(也就是此时头节点)
    link_node_p pdel = p->front;
    // 3. 将头指针向后移动一个单位
    p->front = p->front->next;
    // 4. 释放要删除节点
    free(pdel);
    // 5. 将此时头指针指所指节点的数据出队
    return p->front->data;
}

//求队列长度的函数
int lengthLinkQueue(linkqueue_p p)
{
    int len = 0;
    link_node_p t = p->front;
    while (t->next != NULL)
    {
        t = t->next;
        len++;
    }
    return len;
}

int main(int argc, char const *argv[])
{
    linkqueue_p p = createEmptyLinkQueue();
    for (int i = 1; i < 5; i++)
        inLinkQueue(p, i);
    printf("len = %d\n", lengthLinkQueue(p));
    while (!isEmptyLinkQueue(p))
        printf("%d\n", outLinkQueue(p)); //1 2 3 4 先进先出

    return 0;
}

Python实现链式队列

# 1、定义链式队列节点
class Node:
    def __init__(self, value):
        self.data = value  # 数据域
        self.next = None  # 指针域


# 定义队列函数
class LinkQueue:
    # 队列初始化
    def __init__(self):
        self.front = Node(None)  # 相当于队列的头指针
        self.rear = self.front  # 相当于队列的尾指针

    # 2、判断队列是否为空
    def is_empty(self):
        return self.front.next is None

    # 3、元素入队
    def InLinkQueue(self, data):
        new_node = Node(data)
        # 将新节点连接到队尾
        self.rear.next = new_node
        # 队尾指针指向新的队尾节点
        self.rear = new_node

    # 4、队列元素出队
    def OutLinkQueue(self):
        if self.is_empty():
            # print("OutLinkQueue error")
            return "error"
        '''
          # 方法一:头节点不动,剩最后一个节点时需将尾结点回到队头,以防下一次入队且正常出队
        del_queue = self.front.next
        if self.front.next == self.rear:
            self.rear = self.front
        # 跨越删除
        self.front.next = del_queue.next
        return del_queue.data
        '''
        # 方法二:
        data = self.front.next.data
        self.front = self.front.next
        return data

    # 5、获取队首元素
    def Get_top(self):
        if self.is_empty():
            return "Get_top error"
        return self.front.next.data

    # 6、遍历队列
    def display(self):
        if self.is_empty():
            print("display error")
            return
        current = self.front
        while current.next:
            current = current.next
            print(current.data)

    # 7、清空队列
    def ClearLinkQueue(self):
        while not self.is_empty():
            self.OutLinkQueue()

    # 8、返回队列长度
    def LengthLinkQueue(self):
        current = self.front
        length = 0
        while current.next:
            current = current.next
            length += 1
        return length


if __name__ == '__main__':
    link_queue = LinkQueue()
    for i in range(6):
        link_queue.InLinkQueue(i)

    print("queue_topdata=",link_queue.Get_top())
    print("queue_len=",link_queue.LengthLinkQueue())

    for _ in range(6):
        print("queue_data", link_queue.OutLinkQueue())

3 拓展

如何用两个栈实现一个队列的功能?简述思想

参考答案

思路:设两个栈,一个用于in一个用于out
实现入队: 如果in栈没满直接入栈,如果满了出栈之后入out栈,这样先入栈的会在out栈的栈顶。
实现出列: 如果out栈不为空直接让数据出栈,如果为空则把in栈的数据依次出栈入out栈, 这样先入栈的数据会在out栈顶。然后再把数据出out栈,来实现出列功能。


网站公告

今日签到

点亮在社区的每一天
去签到