12.实现IQueue(队列+优先队列)

实现IQueue(队列+优先队列)

功能需求

这里我们用纯虚函数来当作接口实现IQeue,实现如下的功能:

/*************************************************************************
        > File Name: 14.cpp
        > Author:Xiao Yuheng
        > Mail:3312638794@qq.com
        > Created Time: Wed Nov  8 15:53:09 2023
 ************************************************************************/
#include <iostream>
#include <functional>
#include <cstring>

using namespace std;

namespace xyh {

bool cmp(int a, int b) {
    return a < b;
}

bool cmp1(int a, int b) {
    return a > b;
}
    
class IQueue {
public:
    virtual void push(int x) = 0;
    virtual void pop() = 0;
    virtual int top() const = 0;
    virtual int front() const = 0;
    virtual bool empty() const = 0;
    virtual int size() const = 0;
    virtual ~IQueue() {}
};

class queue : public IQueue {
public:

};
    
class priority_queue : public IQueue {
public:

};

}

int main() {
    using namespace xyh;
    queue que;
    for (int i = 0; i < 100; i++) {
        que.push(i + 1);
    }
    while (!que.empty()) {
        cout << que.top() << endl;
        que.pop();
    }
    cout << "***************" << endl;
    priority_queue prque;
    for (int i = 0; i < 100; i++) {
        prque.push(i + 1);
    }
    while (!prque.empty()) {
        cout << prque.top() << endl;
        prque.pop();
    }
    cout << "*******************" << endl;
    priority_queue fprque(cmp1);
    for (int i = 0; i < 100; i++) {
        fprque.push(i + 1);
    }
    while (!fprque.empty()) {
        cout << fprque.top() << endl;
        fprque.pop();
    }
    return 0;
}

​ 简单解释一下这段代码需要我们干什么:

命名空间和比较函数

namespace xyh {
    bool cmp(int a, int b) {
        return a < b;
    }

    bool cmp1(int a, int b) {
        return a > b;
    }
}
  • xyh 命名空间中定义了两个比较函数 cmpcmp1,分别用于升序和降序排列。

抽象队列接口类

class IQueue {
public:
    virtual void push(int x) = 0;
    virtual void pop() = 0;
    virtual int top() const = 0;
    virtual int front() const = 0;
    virtual bool empty() const = 0;
    virtual int size() const = 0;
    virtual ~IQueue() {}
};
  • IQueue 是一个抽象类,定义了队列的基本接口,包括 pushpoptopfrontemptysize 函数。这是一个纯虚类,没有具体的实现。

queue 类

cppCopy codeclass queue : public IQueue {
public:
    // 这里应该添加具体的实现
};
  • queue 类继承自 IQueue 接口,但在代码中没有给出具体的实现。在程序中并没有定义这个类的实际功能。

priority_queue 类

cppCopy codeclass priority_queue : public IQueue {
public:
    // 这里应该添加具体的实现
};
  • priority_queue 类同样继承自 IQueue 接口,但在代码中也没有给出具体的实现。同样,需要在程序中定义这个类的实际功能。

主函数 main

cppCopy codeint main() {
    using namespace xyh;
    queue que;
    // ... (对队列 que 进行操作)

    priority_queue prque;
    // ... (对优先队列 prque 进行操作)

    priority_queue fprque(cmp1);
    // ... (对具有自定义比较函数的优先队列 fprque 进行操作)

    return 0;
}
  • main 函数中创建了一个 queue 对象和两个 priority_queue 对象,分别进行了操作。具体的操作没有在代码中给出,但是通过 pushtoppop 函数来模拟对队列和优先队列的基本操作。在第三个 priority_queue 对象中使用了自定义的比较函数 cmp1

队列实现

这是一个C++队列的实现,扩展了IQueue接口。

int *copy_int(int *now_begin, int *old_begin, int *old_end) {
    memmove(now_begin, old_begin, sizeof(int) * (old_end - old_begin));
    return now_begin + (old_end - old_begin);
}

class queue : public IQueue {
public:
    // 构造函数
    queue(int n = 0) : first(new int[n]), now(first), last(first + n) {}
    // 将新元素推入队列
    void push(int x) override {
        if (now == last) {
            Expansion();
        }
        *(now++) = x;
    }
    // 从队列中弹出前面的元素
    void pop() override {
        if (empty()) return;
        *(first++);
    }
    // 获取前面元素的值
    int top() const override { return *first; }
    // 获取前面元素的值(与`top`相同)
    int front() const override { return *first; }
    // 检查队列是否为空
    bool empty() const override { return first == now; }
    // 获取队列的大小
    int size() const override { return now - first; }

private:
    // 辅助函数,在需要时扩展队列
    void Expansion() {
        if (now != last) return;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_first = new int[new_size];
        int *new_now = new_first;
        new_now = copy_int(new_first, first, last);
        delete[] first;
        first = new_first;
        now = new_now;
        last = new_first + new_size;
    }
    // 成员变量
    int *first;
    int *now;
    int *last;
};

解释:

  • 构造函数:使用给定的大小或默认大小为0初始化队列。
  • push(int x):将新元素 x 添加到队列中。如果队列已满,则调用Expansion函数增加其大小。
  • pop():从队列中删除前面的元素。如果队列为空,则不执行任何操作。
  • top()front():返回前面元素的值,而不移除它。
  • empty():检查队列是否为空。
  • size():返回队列的大小。

​ 这里我们简单实现了一下队列的一个接口,这里我们的代码还有很大的优化空间,上述代码中如果队列中的元素pop出栈之后,这个空间将不在使用,浪费内存的使用,我们来实现一个循环队列进行存储:

循环队列实现

class queue : public IQueue {
public:
    // 构造函数
    queue(int n = 10) : data(new int[n]), head(0), tail(-1), count(0), total(n) {}
    // 将新元素推入队列
    void push(int x) override {
        if (full()) {
            Expansion();
        }
        count += 1, tail = (tail + 1) % total;
        data[tail] = x;
    }
    // 从队列中弹出前面的元素
    void pop() override {
        if (empty()) return;
        count -= 1, head = (head + 1) % total;
    }
    // 获取前面元素的值
    int top() const override { return data[head]; }
    // 获取前面元素的值(与`top`相同)
    int front() const override { return data[head]; }
    // 检查队列是否为空
    bool empty() const override { return count == 0; }
    // 获取队列的大小
    int size() const override { return count; }
    // 检查队列是否已满
    int full() const { return count == total; }

private:
    // 辅助函数,在需要时扩展队列
    void Expansion() {
        if (!full()) return;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_data = new int[new_size];
        int *now_data = new_data;
        int cnt = count;
        now_data = copy_int(now_data, data + head, data + total);
        now_data = copy_int(now_data, data, data + tail);
        delete[] data;
        data = new_data;
        head = 0, tail = count - 1;
        total = new_size;
        cout << total << endl;
    }
    // 成员变量
    int *data;
    int head, tail, count, total;
};

解释:

  • 构造函数:使用给定的大小或默认大小为10初始化队列。
  • push(int x):将新元素 x 添加到队列中。如果队列已满,则调用Expansion函数增加其大小。
  • pop():从队列中删除前面的元素。如果队列为空,则不执行任何操作。
  • top()front():返回前面元素的值,而不移除它。
  • empty():检查队列是否为空。
  • size():返回队列的大小。
  • full():检查队列是否已满。
  • Expansion():辅助函数,在需要时扩展队列。扩展后会将原有数据复制到新的存储空间中。

我们这里的扩展队列函数太长了,我们来进行优化一下:

class queue : public IQueue {
public:
    queue(int n = 10) : data(new int[n]), head(0), tail(-1), count(0), total(n) {}
    void push(int x) override {
        if (full()) {
            Expansion();
        }
        count += 1, tail = (tail + 1) % total;
        data[tail] = x;
    }
    void pop() override {
        if (empty()) return ;
        count -= 1, head = (head + 1) % total;
    }
    int top() const override { return data[head]; }
    int front() const override { return data[head]; }
    bool empty() const override { return count == 0; }
    int size() const override { return count; }
    int full() const { return count == total; }
    ~queue() { delete[] data; }
    void swap(queue &q) {
        std::swap(this->data, q.data);
        std::swap(this->head, q.head);
        std::swap(this->tail, q.tail);
        std::swap(this->count, q.count);
        std::swap(this->total, q.total);
    }
private:
    void Expansion() {
        int old_size = size();
        int len = old_size != 0 ? old_size * 2 : 1;
        queue q(len);
        while (!empty()) {
            q.push(top());
            pop();
        }
        swap(q);
    }
    int *data;
    int head, tail, count, total;
};

​ 我们可以直接开辟一个原对象两倍大小的对象,然后把原对象的元素插入到新对象中去,最后交换两个对象的所有成员属性,最后q对象会调用析构函数,自动释放掉内存。到此,我们的队列就实现完成了。

优先队列

class priority_queue : public IQueue {
public:
    priority_queue(function<bool(int, int)> cmp = less<int>(), int n = 10)
                : first(new int[n]), now(first),
                last(first + n), cmp(cmp) {}
    void push(int x) override {
        if (now == last) {
            Expansion();
        }
        *(now++) = x;
        int temp = now - first;
        while (temp >> 1 && cmp(first[temp / 2 - 1], first[temp - 1])) {
            swap(first[temp - 1], first[temp / 2 - 1]);
            temp >>= 1;
        }
    }
    void pop() override {
        if (empty()) return ;
        *first = *(--now);
        int temp = 1, cnt = now - first;
        while (temp << 1 <= cnt) {
            int ind = temp, l = temp * 2, r = temp * 2 + 1;
            if (cmp(first[temp - 1], first[l - 1])) temp = l;
            if (r <= cnt && cmp(first[temp - 1], first[r - 1])) temp = r;
            if (temp == ind) break;
            swap(first[ind - 1], first[temp - 1]);
        }
    }
    int top() const override { return *first; }
    int front() const override { return *first; }
    bool empty() const override { return first == now; }
    int size() const override { return now - first; }

private:
    void Expansion() {
        if (now != last) return ;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_first = new int[new_size];
        int *new_now = new_first;
        new_now = copy_int(new_first, first, last);
        delete[] first;
        first = new_first;
        now = new_now;
        last = new_first + new_size;
    }
    int *first;
    int *now;
    int *last;
    function<bool(int, int)> cmp;
};

构造函数

cppCopy codepriority_queue(function<bool(int, int)> cmp = less<int>(), int n = 10)
    : first(new int[n]), now(first),
      last(first + n), cmp(cmp) {}
  • 构造函数接受两个参数,一个是比较函数 cmp,默认为 less<int>(),另一个是队列的初始大小 n,默认为 10。
  • 使用初始化列表初始化了类的成员变量。
  • first 指向队列的起始位置,now 指向当前元素的位置,last 指向队列的末尾位置,cmp 是用于比较元素大小的函数。

push 函数

cppCopy codevoid push(int x) override {
    if (now == last) {
        Expansion();
    }
    *(now++) = x;
    int temp = now - first;
    while (temp >> 1 && cmp(first[temp / 2 - 1], first[temp - 1])) {
        swap(first[temp - 1], first[temp / 2 - 1]);
        temp >>= 1;
    }
}
  • push 函数用于将元素推入优先队列。
  • 如果队列已满,调用 Expansion 函数扩展队列。
  • 将元素 x 放入队列末尾,然后通过循环将其调整到合适的位置,确保父节点的值大于或等于子节点的值。

pop 函数

cppCopy codevoid pop() override {
    if (empty()) return ;
    *first = *(--now);
    int temp = 1, cnt = now - first;
    while (temp << 1 <= cnt) {
        int ind = temp, l = temp * 2, r = temp * 2 + 1;
        if (cmp(first[temp - 1], first[l - 1])) temp = l;
        if (r <= cnt && cmp(first[temp - 1], first[r - 1])) temp = r;
        if (temp == ind) break;
        swap(first[ind - 1], first[temp - 1]);
    }
}
  • pop 函数用于从优先队列中移除最大元素。
  • 如果队列为空,函数直接返回。
  • 将队列的首元素替换为队列末尾的元素,并通过循环将其调整到合适的位置,确保父节点的值大于或等于子节点的值。

top 和 front 函数

cppCopy codeint top() const override { return *first; }
int front() const override { return *first; }
  • topfront 函数返回队列的首元素值。

empty 和 size 函数

cppCopy codebool empty() const override { return first == now; }
int size() const override { return now - first; }
  • empty 函数检查队列是否为空。
  • size 函数返回队列中元素的数量。

Expansion 函数

cppCopy codeprivate:
    void Expansion() {
        if (now != last) return ;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_first = new int[new_size];
        int *new_now = new_first;
        new_now = copy_int(new_first, first, last);
        delete[] first;
        first = new_first;
        now = new_now;
        last = new_first + new_size;
    }
  • Expansion 函数用于在队列满时扩展队列的大小。
  • 如果队列未满,函数直接返回。
  • 计算新队列的大小,创建新的数组,并将原数组的元素复制到新数组。
  • 最后更新队列的指针和大小。

完整代码:

/*************************************************************************
        > File Name: 14.cpp
        > Author:Xiao Yuheng
        > Mail:3312638794@qq.com
        > Created Time: Wed Nov  8 15:53:09 2023
 ************************************************************************/

#include <iostream>
#include <functional>
#include <cstring>

using namespace std;

namespace xyh {

bool cmp(int a, int b) {
    return a < b;
}

bool cmp1(int a, int b) {
    return a > b;
}

int *copy_int(int *now_begin, int *old_begin, int *old_end) {
    memmove(now_begin, old_begin, sizeof(int) * (old_end - old_begin));
    return now_begin + (old_end - old_begin);
    }

class IQueue {
public:
    virtual void push(int x) = 0;
    virtual void pop() = 0;
    virtual int top() const = 0;
    virtual int front() const = 0;
    virtual bool empty() const = 0;
    virtual int size() const = 0;
    virtual ~IQueue() {}
};

/*
class queue : public IQueue {
public:
    queue(int n = 0) : first(new int[n]), now(first), last(first + n) {}
    void push(int x) override {
        if (now == last) {
            Expansion();
        }
        *(now++) = x;
    }
    void pop() override {
        if (empty()) return ;
        *(first++);
    }
    int top() const override { return *first; }
    int front() const override { return *first; }
    bool empty() const override { return first == now; }
    int size() const override { return now - first; }
private:
    void Expansion() {
        if (now != last) return ;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_first = new int[new_size];
        int *new_now = new_first;
        new_now = copy_int(new_first, first, last);
        delete[] first;
        first = new_first;
        now = new_now;
        last = new_first + new_size;
    }
    int *first;
    int *now;
    int *last;
};
*/

class queue : public IQueue {
public:
    queue(int n = 10) : data(new int[n]), head(0), tail(-1), count(0), total(n) {}
    void push(int x) override {
        if (full()) {
            Expansion();
        }
        count += 1, tail = (tail + 1) % total;
        data[tail] = x;
    }
    void pop() override {
        if (empty()) return ;
        count -= 1, head = (head + 1) % total;
    }
    int top() const override { return data[head]; }
    int front() const override { return data[head]; }
    bool empty() const override { return count == 0; }
    int size() const override { return count; }
    int full() const { return count == total; }
    ~queue() { delete[] data; }
    void swap(queue &q) {
        std::swap(this->data, q.data);
        std::swap(this->head, q.head);
        std::swap(this->tail, q.tail);
        std::swap(this->count, q.count);
        std::swap(this->total, q.total);
    }
private:
    /*
    void Expansion() {
        if (!full()) return ;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_data = new int[new_size];
        int *now_data = new_data;
        int cnt = count;
        now_data = copy_int(now_data, data + head, data + total);
        now_data = copy_int(now_data, data, data + tail);
        delete[] data;
        data = new_data;
        head = 0, tail = count - 1;
        total = new_size;
        cout << total << endl;
    }
    */
    void Expansion() {
        int old_size = size();
        int len = old_size != 0 ? old_size * 2 : 1;
        queue q(len);
        while (!empty()) {
            q.push(top());
            pop();
        }
        swap(q);
    }
    int *data;
    int head, tail, count, total;
};

class priority_queue : public IQueue {
public:
    priority_queue(function<bool(int, int)> cmp = less<int>(), int n = 10)
                : first(new int[n]), now(first),
                last(first + n), cmp(cmp) {}
    void push(int x) override {
        if (now == last) {
            Expansion();
        }
        *(now++) = x;
        int temp = now - first;
        while (temp >> 1 && cmp(first[temp / 2 - 1], first[temp - 1])) {
            swap(first[temp - 1], first[temp / 2 - 1]);
            temp >>= 1;
        }
    }
    void pop() override {
        if (empty()) return ;
        *first = *(--now);
        int temp = 1, cnt = now - first;
        while (temp << 1 <= cnt) {
            int ind = temp, l = temp * 2, r = temp * 2 + 1;
            if (cmp(first[temp - 1], first[l - 1])) temp = l;
            if (r <= cnt && cmp(first[temp - 1], first[r - 1])) temp = r;
            if (temp == ind) break;
            swap(first[ind - 1], first[temp - 1]);
        }
    }
    int top() const override { return *first; }
    int front() const override { return *first; }
    bool empty() const override { return first == now; }
    int size() const override { return now - first; }

private:
    void Expansion() {
        if (now != last) return ;
        int old_size = size();
        int new_size = old_size != 0 ? old_size * 2 : 1;
        int *new_first = new int[new_size];
        int *new_now = new_first;
        new_now = copy_int(new_first, first, last);
        delete[] first;
        first = new_first;
        now = new_now;
        last = new_first + new_size;
    }
    int *first;
    int *now;
    int *last;
    function<bool(int, int)> cmp;
};

}

int main() {
    using namespace xyh;
    queue que;
    for (int i = 0; i < 100; i++) {
        que.push(i + 1);
    }
    while (!que.empty()) {
        cout << que.top() << endl;
        que.pop();
    }
    cout << "***************" << endl;
    priority_queue prque;
    for (int i = 0; i < 100; i++) {
        prque.push(i + 1);
    }
    while (!prque.empty()) {
        cout << prque.top() << endl;
        prque.pop();
    }
    cout << "*******************" << endl;
    priority_queue fprque(cmp1);
    for (int i = 0; i < 100; i++) {
        fprque.push(i + 1);
    }
    while (!fprque.empty()) {
        cout << fprque.top() << endl;
        fprque.pop();
    }
    return 0;
}
  • 14
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值