【C++】简易栈的实现

程序说明

一、博客日期

本文第一次发布
2023年03月19日22点30分
Authors
THDMI

二、引言

简单记录下,模板的使用,目前尚且还有一个问题就是,在重载加法运算符的过程中,使用malloc产生的要怎么手动释放,目前在主函数好像不能直接free了,不确定它会不会自动析构。

代码主要描述了一个简单的,实现的过程,太久没用C++了,算是复习一下,另外模板也是第二次用,重载运算符是第一次用,嗯,之前都完全没用到,虽然看过教程,这次算是动手实践,但是内存泄露还是存在,换成指针后允许手动释放内存,但还是不够优雅。

实际上想加入根据传入的数组初始化栈的,但是想了很久没想出要怎么在未知数组长度情况下,计算一个数组类型的一级指针参数的长度。

因为只是简单记录,而且是,所以暂时不写注释了,有两个类,一个是None,用于标识什么都没有,因为模板不允许用void*,另一个是Rt类,用于返回时携带操作成功或失败,以及必要的结果,如果没有结果,应该使用Rt<None>

版权声明

本工程作品均为本文作者撰写,无其他参考,允许使用在任何场景,作品遵循GPLv3.0开源协议。转载本文请标注出处。

开发环境

一、开发配置

操作系统
Microsoft Windows10 家庭版 20H2

二、开发工具

软件依赖版本类型版本号
LightlyPerson0.7.9

效果演示

具体测试理论效果参考测试部分。
效果

核心代码

一、构造类

(一)默认长度构造

template <typename T> Stack<T>::Stack() {
    this->stack_array = (T*)malloc(sizeof(T) * this->default_stack_len);
    this->len_max = this->default_stack_len;
    this->len = 0;
}

(二)带自扩容构造

template <typename T> Stack<T>::Stack(bool is_auto_expand) {
    this->stack_array = (T*)malloc(sizeof(T) * this->default_stack_len);
    this->len_max = this->default_stack_len;
    this->len = 0;
    this->is_auto_expand = true;
}

(三)带初始长度构造

template <typename T> Stack<T>::Stack(int stack_len) {
    this->stack_array = (T*)malloc(sizeof(T) * stack_len);
    this->len_max = stack_len;
    this->len = 0;
}

(四)析构

template <typename T> Stack<T>::~Stack() {
    if (nullptr == this->stack_array) {
        return;
    }
    free(this->stack_array);
    this->stack_array = nullptr;
}

二、重载运算符

(一)加法重载运算符

  1. 内存泄露版
template <typename T> Stack<T>& Stack<T>::operator+(Stack& stack_add) {
    Stack<T>* new_stack = (Stack<T>*)malloc(sizeof(Stack<T>));
    new_stack->len = 0;
    new_stack->len_max = this->len + stack_add.get_len();
    if (nullptr != new_stack->stack_array) {
        free(new_stack->stack_array);
    }
    new_stack->stack_array = (T*)malloc(sizeof(T) * new_stack->len_max);
    for (int i = 0; i < this->len; i++) {
        new_stack->push(this->stack_array[i]);
    }
    for (int i = 0; i < stack_add.get_len(); i++) {
        new_stack->push(stack_add.stack_array[i]);
    }
    return *new_stack;
}
  1. 手动释放版
template <typename T> Stack<T>* Stack<T>::operator+(Stack& stack_add) {
    Stack<T>* new_stack = (Stack<T>*)malloc(sizeof(Stack<T>));
    new_stack->len = 0;
    new_stack->len_max = this->len + stack_add.get_len();
    if (nullptr != new_stack->stack_array) {
        free(new_stack->stack_array);
    }
    new_stack->stack_array = (T*)malloc(sizeof(T) * new_stack->len_max);
    for (int i = 0; i < this->len; i++) {
        new_stack->push(this->stack_array[i]);
    }
    for (int i = 0; i < stack_add.get_len(); i++) {
        new_stack->push(stack_add.stack_array[i]);
    }
    // You must free the point if you don't need it.
    return new_stack;
}

(二)复合加法重载运算符

template <typename T> Stack<T>& Stack<T>::operator+=(Stack& st) {
    if (nullptr == this->stack_array) {
        return *this;
    }
    if (this->len_max < this->len + st.len) {
        this->len_max += st.len;
    }
    T* temp = (T*)malloc(sizeof(T) * this->len_max);
    for (int i = 0; i < this->len; i++) {
        temp[i] = this->stack_array[i];
    }
    free(this->stack_array);
    this->stack_array = temp;
    temp = nullptr;
    for (int i = 0; i < st.len; i++) {
        this->push(st.stack_array[i]);
    }
    return *this;
}

三、基本操作

(一)入栈

template <typename T> Rt<None> Stack<T>::push(T ele) {
    Rt<None> rt;
    if (this->len_max <= this->len) {
        if (this->is_auto_expand) {
            T *tmp = (T*)malloc(sizeof(T) * (this->len_max + this->default_stack_len));
            this->len_max += this->default_stack_len;
            memcpy(tmp, this->stack_array, this->len * sizeof(T));
            free(this->stack_array);
            this->stack_array = tmp;
        } else {
            rt.flag = false;
            return rt;
        }
    }
    ++this->len;
    this->stack_array[this->len - 1] = ele;
    rt.flag = true;
    return rt;
}

(二)出栈

template <typename T> Rt<int> Stack<T>::pull() {
    Rt<int> rt;
    if (this->len <= 0) {
        rt.flag = false;
        return rt;
    }
    rt.data = this->stack_array[this->len - 1];
    --this->len;
    rt.flag = true;
    return rt;
}

(三)读栈

template <typename T> Rt<int> Stack<T>::read() {
    Rt<int> rt;
    if (this->len <= 0) {
        rt.flag = false;
        return rt;
    }
    rt.data = this->stack_array[len - 1];
    rt.flag = true;
    return rt;
}

(四)获长

template <typename T> int Stack<T>::get_len() {
     return this->len; 
}

(五)打印

template <typename T> void Stack<T>::print() {
    for (int i = 0; i < this->len; i++) {
        std::cout << this->stack_array[i] << "\t";
    }
    std::cout << std::endl;
}

(六)允扩

template <typename T> void Stack<T>::auto_expand_set(bool option) {
    this->is_auto_expand = option;
}

四、测试

(一)测试代码

    Stack<std::string> st1 = Stack<std::string>();
    Stack<std::string> st2 = Stack<std::string>();
    Stack<std::string> st3;
    for (int i = 0; i < 8; i++) {
        st1.push("abc");
    }
    for (int i = 0; i < 12; i++) {
        st2.push("bcd");
    }
    std::cout << "Stack 01: ";
    st1.print();
    std::cout << "\nStack 02: ";
    st2.print();
    st1 += st2;
    std::cout << "\nStack 01: ";
    st1.print();
    st3 = st1 + st2;
    std::cout << "\nStack 03: ";
    st3.print();

(二)应示效果

  1. st1会入栈8个元素,st2会入栈8个元素
  2. 因为st2允许自动扩容,所以还会再入4个元素
  3. st1st2组合,st1会扩容,st2全部元素会追加在st1末尾
  4. st3将拥有实例,装载有组合后的st1,再次与st2组合

全部代码

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iterator>

class None {};

template <typename T> class Rt {
  public:
    bool flag;
    T data;
};

template <typename T> class Stack {
  template <typename S> friend void free_stack(Stack<S>* stack_free);
  
  private:
    int default_stack_len = 8;
    bool is_auto_expand = false;
    T* stack_array;
    int len;
    int len_max;

  public:
    Stack();
    Stack(bool is_auto_expand);
    Stack(int stack_len);
    ~Stack();
    // Stack& operator+(Stack& stack_add);
	Stack* operator+(Stack& stack_add);
    Stack& operator+=(Stack& st);
    void auto_expand_set(bool option);
    int get_len();
    void print();
    Rt<None> push(T ele);
    Rt<int> pull();
    Rt<int> read();
};

template <typename T> Stack<T>* Stack<T>::operator+(Stack& stack_add) {
    Stack<T>* new_stack = (Stack<T>*)malloc(sizeof(Stack<T>));
    new_stack->len = 0;
    new_stack->len_max = this->len + stack_add.get_len();
    if (nullptr != new_stack->stack_array) {
        free(new_stack->stack_array);
    }
    new_stack->stack_array = (T*)malloc(sizeof(T) * new_stack->len_max);
    for (int i = 0; i < this->len; i++) {
        new_stack->push(this->stack_array[i]);
    }
    for (int i = 0; i < stack_add.get_len(); i++) {
        new_stack->push(stack_add.stack_array[i]);
    }
    // You must free the point if you don't need it.
    return new_stack;
}

template <typename T> Stack<T>& Stack<T>::operator+=(Stack& st) {
    if (nullptr == this->stack_array) {
        return *this;
    }
    if (this->len_max < this->len + st.len) {
        this->len_max += st.len;
    }
    T* temp = (T*)malloc(sizeof(T) * this->len_max);
    for (int i = 0; i < this->len; i++) {
        temp[i] = this->stack_array[i];
    }
    free(this->stack_array);
    this->stack_array = temp;
    temp = nullptr;
    for (int i = 0; i < st.len; i++) {
        this->push(st.stack_array[i]);
    }
    return *this;
}

template <typename T> Stack<T>::Stack() {
    this->stack_array = (T*)malloc(sizeof(T) * this->default_stack_len);
    this->len_max = this->default_stack_len;
    this->len = 0;
}

template <typename T> Stack<T>::Stack(bool is_auto_expand) {
    this->stack_array = (T*)malloc(sizeof(T) * this->default_stack_len);
    this->len_max = this->default_stack_len;
    this->len = 0;
    this->is_auto_expand = true;
}

template <typename T> Stack<T>::Stack(int stack_len) {
    this->stack_array = (T*)malloc(sizeof(T) * stack_len);
    this->len_max = stack_len;
    this->len = 0;
}

template <typename T> Stack<T>::~Stack() {
    if (nullptr == this->stack_array) {
        return;
    }
    free(this->stack_array);
    this->stack_array = nullptr;
}

template <typename T> void Stack<T>::auto_expand_set(bool option) {
    this->is_auto_expand = option;
}

template <typename T> int Stack<T>::get_len() {
    return this->len;
}

template <typename T> void Stack<T>::print() {
    for (int i = 0; i < this->len; i++) {
        std::cout << this->stack_array[i] << "\t";
    }
    std::cout << std::endl;
}

template <typename T> Rt<None> Stack<T>::push(T ele) {
    Rt<None> rt;
    if (this->len_max <= this->len) {
        if (this->is_auto_expand) {
            T* tmp = (T*)malloc(sizeof(T) *
                                (this->len_max + this->default_stack_len));
            this->len_max += this->default_stack_len;
            memcpy(tmp, this->stack_array, this->len * sizeof(T));
            // for (int i = 0; i < this->len; i ++) {
            //     tmp[i] = this->stack_array[i];
            // }
            free(this->stack_array);
            this->stack_array = tmp;
        } else {
            rt.flag = false;
            return rt;
        }
    }
    ++this->len;
    this->stack_array[this->len - 1] = ele;
    rt.flag = true;
    return rt;
}

template <typename T> Rt<int> Stack<T>::pull() {
    Rt<int> rt;
    if (this->len <= 0) {
        rt.flag = false;
        return rt;
    }
    rt.data = this->stack_array[this->len - 1];
    --this->len;
    rt.flag = true;
    return rt;
}

template <typename T> Rt<int> Stack<T>::read() {
    Rt<int> rt;
    if (this->len <= 0) {
        rt.flag = false;
        return rt;
    }
    rt.data = this->stack_array[len - 1];
    rt.flag = true;
    return rt;
}

template <typename T> void free_stack(Stack<T>* stack_free) {
    stack_free->~Stack();
    free(stack_free);
    stack_free = nullptr;
}

int main() {
    Stack<std::string> st1 = Stack<std::string>();
    Stack<std::string> st2 = Stack<std::string>(true);
    // Stack<std::string> st3;
    Stack<std::string>* st3;
    for (int i = 0; i < 8; i++) {
        st1.push("abc");
    }
    for (int i = 0; i < 12; i++) {
        st2.push("bcd");
    }
    std::cout << "Stack 01: ";
    st1.print();
    std::cout << "\nStack 02: ";
    st2.print();
    st1 += st2;
    std::cout << "\nStack 01: ";
    st1.print();
    st3 = st1 + st2;
    std::cout << "\nStack 03: ";
    st3->print();
    free_stack(st3);
}

结语

多看、多查、多练

参考文献

[1] C++ Primer 第5版 中文版 (Stanley B. Lippman等著,王刚等译)


END

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用一个队列来实现一个,具体思路如下: 1. 定义一个队列结构体,包含一个数组和两个指针 front 和 rear,分别指向队列的头和尾。 2. 定义一个结构体,包含一个队列的指针和一个整数 top,表示顶元素的下标。 3. 入操作时,将元素插入队列的尾部,同时更新 top 的值。 4. 出操作时,将队列的 rear 指针指向的元素弹出,同时更新 top 的值。 5. 判断是否为空时,判断 top 的值是否为 -1。 下面是示例代码: ```c #include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 // 定义队列结构体 typedef struct { int data[MAXSIZE]; int front; // 队首指针 int rear; // 队尾指针 } Queue; // 初始化队列 void initQueue(Queue *q) { q->front = q->rear = -1; } // 判断队列是否为空 int isEmpty(Queue *q) { return q->front == -1; } // 判断队列是否已满 int isFull(Queue *q) { return (q->rear + 1) % MAXSIZE == q->front; } // 入队操作 void enqueue(Queue *q, int x) { if (isFull(q)) { printf("Queue is full.\n"); return; } if (isEmpty(q)) { q->front = q->rear = 0; } else { q->rear = (q->rear + 1) % MAXSIZE; } q->data[q->rear] = x; } // 出队操作 int dequeue(Queue *q) { if (isEmpty(q)) { printf("Queue is empty.\n"); return -1; } int x = q->data[q->front]; if (q->front == q->rear) { q->front = q->rear = -1; } else { q->front = (q->front + 1) % MAXSIZE; } return x; } // 定义结构体 typedef struct { Queue *q; int top; // 顶指针 } Stack; // 初始化 void initStack(Stack *s) { s->q = (Queue *) malloc(sizeof(Queue)); initQueue(s->q); s->top = -1; } // 判断是否为空 int stackIsEmpty(Stack *s) { return s->top == -1; } // 入操作 void push(Stack *s, int x) { enqueue(s->q, x); s->top++; } // 出操作 int pop(Stack *s) { if (stackIsEmpty(s)) { printf("Stack is empty.\n"); return -1; } int i, x; // 将队列中的前 top 个元素出队再入队,实现的弹出操作 for (i = 0; i < s->top; i++) { x = dequeue(s->q); enqueue(s->q, x); } // 弹出顶元素 x = dequeue(s->q); // top 减 1 s->top--; return x; } int main() { Stack s; initStack(&s); push(&s, 1); push(&s, 2); push(&s, 3); printf("%d\n", pop(&s)); // 3 printf("%d\n", pop(&s)); // 2 printf("%d\n", pop(&s)); // 1 printf("%d\n", pop(&s)); // Stack is empty. return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值