队列和栈

本文详细介绍了队列和栈这两种基本数据结构,包括它们的实现方式、应用场景以及与广度优先搜索(BFS)和深度优先搜索(DFS)的关系。文章通过实例探讨了如何使用队列和栈解决实际问题,如岛屿数量计算、转盘锁问题、完全平方数求解等。此外,还讨论了如何用栈实现队列,以及用队列实现栈的策略。最后,总结了队列和栈的区别及它们在算法设计中的重要性。
摘要由CSDN通过智能技术生成

1.队列的实现

#include<iostream>
#include<vector>

using namespace std;

class MyQueue {
    private:
        // store elements
        vector<int> data;
        // a pointer to indicate the start position
        int p_start;
    public:
        MyQueue() {p_start = 0;}
        /** Insert an element into the queue. Return true if the operation is successful. */
        bool enQueue(int x) {
            data.push_back(x);
            return true;
        }
        /** Delete an element from the queue. Return true if the operation is successful. */
        bool deQueue() {
            if (isEmpty()) {
                return false;
            }
            p_start++;
            return true;
        };
        /** Get the front item from the queue. */
        int Front() {
            return data[p_start];
        };
        /** Checks whether the queue is empty or not. */
        bool isEmpty()  {
            return p_start >= data.size();
        }
};

int main() {
    MyQueue q;
    q.enQueue(5);
    q.enQueue(3);
    if (!q.isEmpty()) {
        cout << q.Front() << endl;
    }
    q.deQueue();
    if (!q.isEmpty()) {
        cout << q.Front() << endl;
    }
    q.deQueue();
    if (!q.isEmpty()) {
        cout << q.Front() << endl;
    }
}

在这种情况下很容易造成内存空间的浪费。

2.循环队列

注意这里内存大小k+1

#include<iostream>
using namespace std;

class MyCircularQueue {

private:
    int* data;
    int size;
    int head;
    int tail;
public:
    /** Initialize your data structure here. Set the size of the queue to be k. */
    MyCircularQueue(int k) {
        data = new int[k+1];
        size = k+1;
        head = 0;
        tail = 0;
    }

    /** Insert an element into the circular queue. Return true if the operation is successful. */
    bool enQueue(int value) {
        if(!isFull())
        {
            tail = (tail + 1)%size;
            data[tail] = value;
            return true;
        }
        return false;
    }

    /** Delete an element from the circular queue. Return true if the operation is successful. */
    bool deQueue() {
        if(isEmpty())
            return false;
        head = (head + 1) %size;
        return true;
    }

    /** Get the front item from the queue. */
    int Front() {
        if(isEmpty())
            return -1;
        return data[(head+1)%size];
    }

    /** Get the last item from the queue. */
    int Rear() {
        if(isEmpty())
            return -1;
        return data[tail];
    }

    /** Checks whether the circular queue is empty or not. */
    bool isEmpty() {
        if(head == tail)
            return true;
        return false;
    }

    /** Checks whether the circular queue is full or not. */
    bool isFull() {
        if((tail + 1) %size == head)
            return true;
        return false;
     }
};

int main() {
    MyCircularQueue q(3);
    cout<<q.enQueue(1)<<endl;
    cout<<q.enQueue(2)<<endl;
    cout<<q.enQueue(3)<<endl;
    cout<<q.enQueue(4)<<endl;

    cout<<q.Rear()<<endl;
    cout<<q.isFull()<<endl;
    cout<<q.deQueue()<<endl;
    cout<<q.enQueue(4)<<endl;
    cout<<q.Rear()<<endl;
}

3.队列和 BFS

BFS 的两个主要方案:遍历找出最短路径

(1)BFS模板1

/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    Queue<Node> queue;  // store all nodes which are waiting to be processed
    int step = 0;       // number of steps neeeded from root to current node
    // initialize
    add root to queue;
    // BFS
    while (queue is not empty) {
        step = step + 1;
        // iterate the nodes which are already in the queue
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                add next to queue;
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}
  1. 如代码所示,在每一轮中,队列中的结点是等待处理的结点
  2. 在每个更外一层的 while 循环之后,我们距离根结点更远一步。变量 step 指示从根结点到我们正在访问的当前结点的距离。

(2)BFS模板2

有时,确保我们永远不会访问一个结点两次很重要。否则,我们可能陷入无限循环。如果是这样,我们可以在上面的代码中添加一个哈希集来解决这个问题。这是修改后的伪代码:

/**
 * Return the length of the shortest path between root and target node.
 */
int BFS(Node root, Node target) {
    Queue<Node> queue;  // store all nodes which are waiting to be processed
    Set<Node> used;     // store all the used nodes
    int step = 0;       // number of steps neeeded from root to current node
    // initialize
    add root to queue;
    add root to used;
    // BFS
    while (queue is not empty) {
        step = step + 1;
        // iterate the nodes which are already in the queue
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
            Node cur = the first node in queue;
            return step if cur is target;
            for (Node next : the neighbors of cur) {
                if (next is not in used) {
                    add next to queue;
                    add next to used;
                }
            }
            remove the first node from queue;
        }
    }
    return -1;          // there is no path from root to target
}

200.岛屿的个数

给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

示例 1:

输入:
11110
11010
11000
00000

输出: 1

示例 2:

输入:
11000
11000
00100
00011

输出: 3

思路:循环遍历每个点,如果该点是0,则跳过;如果是1,加入队列并将该点改为0,避免重复访问。然后进行广搜,取出队首元素,搜索该点周围四个点,如果有1就加入队列,并将1改为0,否则就跳过,当队列空时,一块岛屿搜索完毕,岛屿数目加1。进入下一块搜索,如此下去。。。
搜索时注意数组是否越界

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        if(grid.empty() || grid[0].empty())
            return 0;
        int m = grid.size(), n = grid[0].size();
        int res = 0;
        queue<pair<int,int>> island;
        pair<int, int> pos;
      
        for(int i = 0; i < m;i++)
            for(int j = 0; j < n; j++)
            {
                if(grid[i][j] == '0')
                    continue;
                else
                {
                    pos.first = i;
                    pos.second = j;
                    island.push(pos);
                    grid[i][j] = '0';
                    while(!island.empty())
                    {
                        pos = island.front();
                        island.pop();
                        int x = pos.first;
                        int y = pos.second;
                        if(x-1 >= 0 && grid[x-1][y] == '1')
                        {
                            pos.first = x-1;
                            pos.second = y;
                            island.push(pos);
                            grid[x-1][y] = '0';
                        }
                        if(x+1 < m && grid[x+1][y] == '1')
                        {
                            pos.first = x+1;
                            pos.second = y;
                            island.push(pos);
                            grid[x+1][y] = '0';
                        }
                        if(y-1 >= 0 && grid[x][y-1] == '1')
                        {
                            pos.first = x;
                            pos.second = y-1;
                            island.push(pos);
                            grid[x][y-1] = '0';
                        }
                        if(y+1 < n && grid[x][y+1] == '1')
                        {
                            pos.first = x;
                            pos.second = y+1;
                            island.push(pos);
                            grid[x][y+1] = '0';
                        }
                    }
                    res++;
                }
                
            }
        return res;
    }
};</
C语言中可以使用数组或链表来实现队列。 1. 队列 使用数组实现队列,需要定义一个指向队列头的指针front和一个指向队列尾的指针rear,队列的长度为maxsize。具体实现如下: ``` #define MAXSIZE 100 typedef struct { int data[MAXSIZE]; int front, rear; } Queue; void initQueue(Queue *q) { q->front = q->rear = 0; } int isQueueFull(Queue *q) { return (q->rear + 1) % MAXSIZE == q->front; } int isQueueEmpty(Queue *q) { return q->front == q->rear; } void enqueue(Queue *q, int x) { if (isQueueFull(q)) { printf("Queue is full\n"); return; } q->data[q->rear] = x; q->rear = (q->rear + 1) % MAXSIZE; } int dequeue(Queue *q) { if (isQueueEmpty(q)) { printf("Queue is empty\n"); return -1; } int x = q->data[q->front]; q->front = (q->front + 1) % MAXSIZE; return x; } ``` 其中,initQueue函数用于初始化队列;isQueueFull函数和isQueueEmpty函数分别用于判断队列是否已满和是否为空;enqueue函数用于入队;dequeue函数用于出队。注意,在队列满或空时,需要对应处理。 使用链表实现队列,需要定义一个链表节点Node,以及一个指向队列头节点和队列尾节点的指针head和tail。具体实现如下: ``` typedef struct Node { int data; struct Node *next; } Node; typedef struct { Node *head, *tail; } Queue; void initQueue(Queue *q) { q->head = q->tail = NULL; } int isQueueEmpty(Queue *q) { return q->head == NULL; } void enqueue(Queue *q, int x) { Node *newNode = (Node *)malloc(sizeof(Node)); newNode->data = x; newNode->next = NULL; if (isQueueEmpty(q)) { q->head = q->tail = newNode; } else { q->tail->next = newNode; q->tail = newNode; } } int dequeue(Queue *q) { if (isQueueEmpty(q)) { printf("Queue is empty\n"); return -1; } int x = q->head->data; Node *temp = q->head; q->head = q->head->next; if (q->head == NULL) { q->tail = NULL; } free(temp); return x; } ``` 其中,initQueue函数用于初始化队列;isQueueEmpty函数用于判断队列是否为空;enqueue函数用于入队;dequeue函数用于出队。注意,在队列为空时,需要对应处理。 2. 使用数组实现,需要定义一个指向顶的指针top,的长度为maxsize。具体实现如下: ``` #define MAXSIZE 100 typedef struct { int data[MAXSIZE]; int top; } Stack; void initStack(Stack *s) { s->top = -1; } int isStackFull(Stack *s) { return s->top == MAXSIZE - 1; } int isStackEmpty(Stack *s) { return s->top == -1; } void push(Stack *s, int x) { if (isStackFull(s)) { printf("Stack is full\n"); return; } s->top++; s->data[s->top] = x; } int pop(Stack *s) { if (isStackEmpty(s)) { printf("Stack is empty\n"); return -1; } int x = s->data[s->top]; s->top--; return x; } ``` 其中,initStack函数用于初始化;isStackFull函数和isStackEmpty函数分别用于判断是否已满和是否为空;push函数用于入;pop函数用于出。注意,在满或空时,需要对应处理。 使用链表实现,需要定义一个链表节点Node,以及一个指向顶节点的指针top。具体实现如下: ``` typedef struct Node { int data; struct Node *next; } Node; typedef struct { Node *top; } Stack; void initStack(Stack *s) { s->top = NULL; } int isStackEmpty(Stack *s) { return s->top == NULL; } void push(Stack *s, int x) { Node *newNode = (Node *)malloc(sizeof(Node)); newNode->data = x; newNode->next = s->top; s->top = newNode; } int pop(Stack *s) { if (isStackEmpty(s)) { printf("Stack is empty\n"); return -1; } int x = s->top->data; Node *temp = s->top; s->top = s->top->next; free(temp); return x; } ``` 其中,initStack函数用于初始化;isStackEmpty函数用于判断是否为空;push函数用于入;pop函数用于出。注意,在为空时,需要对应处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值