c++ 队列_经典数据结构与算法(一):Python/C/C ++实现堆栈和队列

 一、堆栈   

堆栈是编程中有用的数据结构。就像一堆盘子彼此叠放。

81fb6f81c13ffd986e880e28318d3620.png
堆栈表示类似于一堆盘子

想一想用这样一堆盘子可以做的事情

  • 在上面放一个新盘子

  • 卸下顶部盘子

  • 持续来回做实验就知道了堆栈的意义

如果要将板放在底部,则必须先卸下顶部的所有板。这种安排称为“后进先出”-放置的最后一个元素是第一个外出元素。


LIFO堆栈原理

用编程的术语来说,将一个元素放在堆栈的顶部称为“推”,而将一个元素删除则称为“弹出”。

19c78af91cb20388acff9411b94a529e.png
堆栈推入和弹出操作

在上图中,尽管元顶部3最后才保留,但它首先被移除-因此它遵循后进先出(LIFO)原则。


堆栈的基本操作

堆栈是一个对象,或更具体地说,是一个允许执行以下操作的抽象数据结构(ADT):

  • Push:将元素添加到堆栈顶部

  • Pop:从堆栈顶部删除元素

  • IsEmpty:检查堆栈是否为空

  • IsFull:检查堆栈是否已满

  • Peek:获取顶部元素的值而不删除它


堆栈数据结构的工作

操作如下:

  1. 称为TOP用于跟踪堆栈中的顶部元素。

  2. 初始化堆栈时,将其值设置为-1,以便可以通过比较来检查堆栈是否为空TOP == -1

  3. 推送元素时,增加了TOP并将新元素放置在所指向的位置TOP

  4. 弹出元素时,返回由指向的元素TOP并降低其值。

  5. 推入之前,检查堆栈是否已满

  6. 弹出之前,检查堆栈是否已为空

aff416afb278b20d6a5abb0597c1e321.png
堆栈数据结构的工作

Python,C和C ++中的堆栈实现

最常见的堆栈实现是使用数组,但是也可以使用列表来实现。

C:

// Stack implementation in C

#include 
#include 
#include "math.h"

/*堆栈最大存储元素基数*/
#define MAX 10

int count = 0;

// Creating a stack
struct stack
{
    int items[MAX];//堆栈元素数组
    int top;
};
typedef struct stack st;

void createEmptyStack(st *s){
    s->top = -1;
}

// Check if the stack is full
int isfull(st *s){
    if (s->top == MAX - 1)
        return 1;
    else
        return 0;
}

// Check if the stack is empty
int isempty(st *s){
    if (s->top == -1)
        return 1;
    else
        return 0;
}

// Add elements into stack
void push(st *s, int newitem){
    if (isfull(s))
    {
        printf("STACK FULL");
    }
    else
    {
        s->top++;//类似索引递增
        s->items[s->top] = newitem;
    }
    count++;//计算次数=个数=添加几个元素
}

// Remove element from stack
void pop(st *s){
    if (isempty(s))
    {
        printf("\n STACK EMPTY \n");
    }
    else
    {
        printf("Item popped= %d", s->items[s->top]);//--的形式从数组里移除元素
        s->top--;//逐一减去
    }
    count--;
    printf("\n");
}

// Print elements of stack
void printStack(st *s){
    printf("Stack: ");
    for (int i = 0; i < count; i++)
    {
        printf("%d ", s->items[i]);
    }
    printf("\n");
}

// 执行 code
int main(){
    int ch,i;
    st *s = (st *)malloc(sizeof(st));
    /*分配一个sizeof(st)大小的空间,并且把该空间的地址赋给st指针类型的p*/
    createEmptyStack(s);

    #if 0
    push(s, 1); //推元素1
    push(s, 2); //推元素2
    push(s, 3); //推元素3
    push(s, 4); //推元素4
    #endif
    /*也可以写成循环的形式*/
    int j;
    for (i = 1; i < 5; i++)
    {
        j = i * (i + 1);
        push(s, j);
        // printf("%d\n",i);
    }
    printStack(s);
    printf("cnt = %d\n", count);

    /*堆栈第一次移除*/
    pop(s);
    printf("\n堆栈第一次移除After popping out\n");
    printStack(s);
    printf("cnt0 = %d\n", count);
    /*堆栈第一次移除*/
    pop(s);
    printf("\n堆栈第二次移除After popping out\n");
    printStack(s);
    printf("cnt1 = %d\n", count);

    system("pause");
    return 0;
}

执行结果:

e641d09accbc15802c94da3922e781c4.png

C++:

// Stack implementation in C++

#include 
#include 

using namespace std;

#define MAX 10
int size_t = 0;

// Creating a stack
struct stack
{
    int items[MAX];
    int top;
};
typedef struct stack st;

void createEmptyStack(st *s){
    s->top = -1;
}

// Check if the stack is full
int isfull(st *s){
    if (s->top == MAX - 1)
        return 1;
    else
        return 0;
}

// Check if the stack is empty
int isempty(st *s){
    if (s->top == -1)
        return 1;
    else
        return 0;
}

// Add elements into stack
void push(st *s, int newitem){
    if (isfull(s))
    {
        printf("STACK FULL");
    }
    else
    {
        s->top++;
        s->items[s->top] = newitem;
    }
    size_t++;
}

// Remove element from stack
void pop(st *s){
    if (isempty(s))
    {
        printf("\n STACK EMPTY \n");
    }
    else
    {
        printf("Item popped= %d", s->items[s->top]);
        s->top--;
    }
    size_t--;
    cout << endl;
}

// Print elements of stack
void printStack(st *s){
    printf("Stack: ");
    for (int i = 0; i < size_t; i++)
    {
        cout << s->items[i] << " ";
    }
    cout << endl;
}

// Driver code
int main(){

    int ch;
    st *s = (st *)malloc(sizeof(st));

    createEmptyStack(s);

    push(s, 1);
    push(s, 2);
    push(s, 3);
    push(s, 4);

    printStack(s);

    pop(s);

    cout << "\nAfter popping out\n";
    printStack(s);



    cin.get();
    return 0;
}

PYTHON:

# Stack implementation in python


# Creating a stack
def create_stack():
    stack = [] #保存
    return stack


# Creating an empty stack
def check_empty(stack):
    return len(stack) == 0


# Adding items into the stack
def push(stack, item):
    stack.append(item)
    # 追加打印出结果 +
    print("pushed item: " + item)



# Removing an element from the stack
def pop(stack):
    if (check_empty(stack)):
        return "stack is empty"
        

    return stack.pop()


stack = create_stack()
# push(stack, str(1))
# push(stack, str(2))
# push(stack, str(3))
# push(stack, str(4))
for item in range(1,10):
    push(stack, str(item))
    pass
print("第 1 次移除popped item: " + pop(stack))
print("移除后剩余的元素stack after popping an element: " + str(stack))

print("第 2 次移除popped item: " + pop(stack))
print("移除后剩余的元素stack after popping an element: " + str(stack))
# 可以按照循环次数来移动

for item in range(5):
    print("第",item+3, "次移除popped item: " + pop(stack))
    print("移除后剩余的元素stack after popping an element: " + str(stack))
    pass

执行结果:

79f6863ce4a243900821687156a9e350.png


堆栈时间复杂度

对于基于数组的堆栈实现,推入和弹出操作需要花费一定的时间,即O(1)因为在两种情况下都只有指针移动。


堆栈数据结构的应用

尽管堆栈是一个易于实现的简单数据结构,但它非常强大。堆栈最常见的用途是:

  • 反转单词-将所有字母叠放并弹出。由于堆栈的LIFO顺序,您将获得相反顺序的字母。

  • 在编译器中-编译器使用堆栈来计算表达式的值,例如2 + 4 / 5 * (7 - 9)将表达式转换为前缀或后缀形式。

  • 在浏览器中-浏览器中的记录“后退”按钮会将您以前访问过的所有URL保存在堆栈中。每次您访问新页面时,它都会被添加到堆栈顶部。当您按下“后退”按钮时,当前URL从堆栈中删除,并访问前一个URL。

二、队列

队列是编程中有用的数据结构。它类似于电影院大厅外面的售票队列,在该队列中,第一个进入队列的人是第一个获得票的人。

队列遵循先进先出(FIFO)规则-先进入的项目也是先进入的项目。

1e82122408a38312518df6b78fff109e.png
队列的FIFO表示

在上图中,由于1在2之前保留在队列中,因此它也是第一个从队列中删除的队列。它遵循FIFO规则。

用编程术语来说,将元素放入队列称为“入队”,而将元素从队列中删除则称为“出队”。


队列的基本操作

队列是一个对象,或更具体地说,是一个允许执行以下操作的抽象数据结构(ADT):

  • Enqueue:将元素添加到队列的末尾

  • Dequeue:从队列的前面删除一个元素

  • IsEmpty:检查队列是否为空

  • IsFull:检查队列是否已满

  • Peek:获取队列最前面的值而不删除它


队列工作

队列操作如下:

  • 两个指针 FRONT 和 REAR

  • FRONT 跟踪队列的第一个元素

  • REAR 跟踪队列的最后一个元素

  • 最初,设定值为 FRONT 和 REAR 至-1

入队操作

  • 检查队列是否已满

  • 对于第一个元素,设置为 FRONT至0

  • 增加 REAR 索引1

  • 在由指向的位置添加新元素 REAR

出队操作

  • 检查队列是否为空

  • 返回所指向的值 FRONT

  • 增加 FRONT 索引1

  • 对于最后一个元素,重置的值FRONT 和 REAR 至-1

3066158ff93ea414825559176f7e700c.png
入队和出队操作

Python,C和C ++中的队列实现

C:

// Queue implementation in C

#include 
#include 
#define SIZE 5

void enQueue(int value);
/*下面声明的还是没有变量,是因为用全局变量代替了*/
void deQueue();
void display();

//定义数组全局变量
int items[SIZE], front = -1, rear = -1;


void enQueue(int value){
    //如果队列后面的已经满了,此时size就不能继续入队列
    if (rear == SIZE - 1)
        printf("\nQueue is Full!!");
    else
    {
        if (front == -1)
            front = 0;
        rear++;//则继续向前递增
        items[rear] = value;//继续插入入栈元素
        printf("\nInserted -> %d", value);
    }
}

void deQueue(){
    //出列
    if (front == -1)
        printf("\nQueue is Empty!!");
    else
    {
        printf("\nDeleted : %d", items[front]);
        front++;
        if (front > rear)
            front = rear = -1;
    }
}

// Function to print the queue
void display(){
    if (rear == -1)
        printf("\nQueue is Empty!!!");
    else
    {
        int i;
        printf("\nQueue elements are:\n");
        for (i = front; i <= rear; i++)
            printf("%d ", items[i]);
    }
    printf("\n");
}

int main(){
    //deQueue is not possible on empty queue
    deQueue();

    //enQueue 5 elements
    enQueue(1);
    enQueue(2);
    enQueue(3);
    enQueue(4);
    enQueue(5);

    //6th element can't be added to queue because queue is full
    enQueue(6);//超过了size[5]的个数范围

    display();//队列索引对应的元素

    //deQueue removes element entered first i.e. 1
    deQueue();

    //Now we have just 4 elements
    display();//展示移除后的对立

    /*再出一次队列*/
    deQueue();
    display(); //展示移除后的对立

    system("pause");
    return 0;
}

执行结果:

95d6625097f76bcbe19a36cd0cbd367b.png

C++

// Queue implementation in C++

#include 
#define SIZE 5

using namespace std;

class Queue
{
private:
    int items[SIZE], front, rear;

public:
    Queue()
    {
        front = -1;
        rear = -1;
    }

    bool isFull(){
        if (front == 0 && rear == SIZE - 1)
        {
            return true;
        }
        return false;
    }

    bool isEmpty(){
        if (front == -1)
            return true;
        else
            return false;
    }

    void enQueue(int element){
        if (isFull())
        {
            cout << "Queue is full";
        }
        else
        {
            if (front == -1)
                front = 0;
            rear++;
            items[rear] = element;
            cout << endl
                 << "Inserted " << element << endl;
        }
    }

    int deQueue(){
        int element;
        if (isEmpty())
        {
            cout << "Queue is empty" << endl;
            return (-1);
        }
        else
        {
            element = items[front];
            if (front >= rear)
            {
                front = -1;
                rear = -1;
            } /* Q has only one element, so we reset the queue after deleting it. */
            else
            {
                front++;
            }
            cout << endl
                 << "Deleted -> " << element << endl;
            return (element);
        }
    }

    void display(){
        /* Function to display elements of Queue */
        int i;
        if (isEmpty())
        {
            cout << endl
                 << "Empty Queue" << endl;
        }
        else
        {
            cout << endl
                 << "Front index-> " << front;
            cout << endl
                 << "Items -> ";
            for (i = front; i <= rear; i++)
                cout << items[i] << " ";
            cout << endl
                 << "Rear index-> " << rear << endl;
        }
    }
};

int main(){
    Queue q;

    //deQueue is not possible on empty queue
    q.deQueue();

    //enQueue 5 elements
    q.enQueue(1);
    q.enQueue(2);
    q.enQueue(3);
    q.enQueue(4);
    q.enQueue(5);

    //6th element can't be added to queue because queue is full
    q.enQueue(6);
    q.display();

    //deQueue removes element entered first i.e. 1
    q.deQueue();
    //Now we have just 4 elements
    q.display();

    //再移动一次
    q.deQueue();
    q.display();
    
    cin.get();
    return 0;
}

执行结果:

6d707f7187418a3a138800bd1ae698de.png

python:

# Circular Queue implementation in Python


class MyCircularQueue():

    def __init__(self, k):
        self.k = k
        self.queue = [None] * k
        self.head = self.tail = -1

    # Insert an element into the circular queue
    def enqueue(self, data):

        if ((self.tail + 1) % self.k == self.head):
            print("The circular queue is full\n")

        elif (self.head == -1):
            self.head = 0
            self.tail = 0
            self.queue[self.tail] = data
        else:
            self.tail = (self.tail + 1) % self.k
            self.queue[self.tail] = data

    # Delete an element from the circular queue
    def dequeue(self):
        if (self.head == -1):
            print("The circular queue is empty\n")

        elif (self.head == self.tail):
            temp = self.queue[self.head]
            self.head = -1
            self.tail = -1
            return temp
        else:
            temp = self.queue[self.head]
            self.head = (self.head + 1) % self.k
            return temp

    def printCQueue(self):
        if(self.head == -1):
            print("No element in the circular queue")

        elif (self.tail >= self.head):
            for i in range(self.head, self.tail + 1):
                print(self.queue[i], end=" ")
            print()
        else:
            for i in range(self.head, self.k):
                print(self.queue[i], end=" ")
            for i in range(0, self.tail + 1):
                print(self.queue[i], end=" ")
            print()


# Your MyCircularQueue object will be instantiated and called as such:
obj = MyCircularQueue(5)
obj.enqueue(1)
obj.enqueue(2)
obj.enqueue(3)
obj.enqueue(4)
obj.enqueue(5)
print("Initial queue")
obj.printCQueue()

obj.dequeue()
print("After removing an element from the queue")
obj.printCQueue()

执行结果:

12e6db208a1eb04ceb3b1585cb14ee9d.png

如您在下图中所看到的,在进行一些入队和出队后,队列的大小已减小。

7131f69985a797707621f3a39cf514af.png
队列限制

只有当所有元素都已出队后,才能在重置队列后使用索引0和1。

后 REAR到达最后一个索引,如果我们可以将多余的元素存储在空白处(0和1),则可以利用这些空白处。这是通过一个称为循环队列的修改队列来实现的 。


复杂度分析

使用数组的队列中入队和出队操作的复杂度为O(1)


队列数据结构的应用

  • CPU调度,磁盘调度

  • 在两个进程之间异步传输数据时。队列用于同步。例如:IO缓冲区,管道,文件IO等

  • 实时系统中的中断处理。

  • 呼叫中心电话系统使用队列来使人们按顺序呼叫


参考文献

https://blog.csdn.net/weixin_41194129/article/details/109281031https://blog.csdn.net/weixin_41194129https://www.zhihu.com/people/zhou-kang-9-28
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值