c++ 栈实现,进制转换,括号匹配,中缀表达式求值

2022年最后一天,复习了栈及栈的应用,转自邓俊辉的数据结构。

栈的实现

列表实现,插入和删除的成本低,但每个节点都要储存前一个节点和下一个节点的值。

template<typename T>
class Stack :public List<T> {
public:
    void push(T const& e) { List<T>::insertAsLast(e); }
    T pop() { return List<T>::remove(List<T>::last()); }
    T& top() { return List<T>::last()->data; }

};

附列表节点和列表的实现

#define Rank int

template<typename T>
struct ListNode;

template<typename T>
using ListNodePosi = ListNode<T>*;

template<typename T>
struct ListNode
{
    //成员
    T data;
    ListNodePosi<T> pred;
    ListNodePosi<T> succ;

    //构造函数
    ListNode() {};
    ListNode(T e, ListNodePosi<T> p = nullptr, ListNodePosi<T> s = nullptr) :
        data(e), pred(p), succ(s) {};

    //操作接口
    ListNodePosi<T> insertAsPred(T const& e);//紧靠当前节点之前插入新节点
    ListNodePosi<T> insertAsSucc(T const& e);//紧靠当前节点之后插入新节点

};

template<typename T>
ListNodePosi<T> ListNode<T>::insertAsPred(T const& e) {
    ListNodePosi<T> newNode = new ListNode(e, this->pred, this);
    this->pred->succ = newNode;
    this->pred = newNode;
    return newNode;
};

template<typename T>
ListNodePosi<T> ListNode<T>::insertAsSucc(T const& e) {
    ListNodePosi<T> newNode = new ListNode(e, this, this->succ);
    this->succ->pred = newNode;
    this->succ=newNode;
    return newNode;
};

列表成员及操作

#pragma once
#include"ListNode.h"
#include<iostream>
using namespace std;

template<typename T>
class List {

private:
    int _size;
    ListNodePosi<T> header, trailer;
protected:
    void init();//列表创建时的初始化
    int clear();//清除所有节点
    void copyNode(ListNodePosi<T> p, int a);//复制列表中自位置p起的n项
public:
    //构造函数
    List() { init(); }//默认
    List(T* A, int n);//给数据,构造列表
    List(List<T> const& L);//复制构造
    List(List<T> const& L, Rank r, int n);//复制列表L中自第r项起的第n项
    List(ListNodePosi<T> p, int n);//复制列表中自位置p起的n项

    //析构函数
    ~List();//清除所有节点,包括header和trailer

    //只读访问接口
    Rank size() const { return _size; }//规模
    bool empty() const { return _size <= 0; }//判空
    T& operator[](Rank r) const;//重载,支持寻秩访问,效率低
    ListNodePosi<T> first() const { return header->succ; }//首节点
    ListNodePosi<T> last() const { return trailer->pred; }//末节点
    bool valid(ListNodePosi<T> p) //判断节点p是否对外合法
    {
        return p && (trailer != p) && (header != p);
    };


    ListNodePosi<T> find(T const&e) const//无序查找
    {
        return find(e, _size, trailer);
    }
    ListNodePosi<T> find(T const& e, int n, ListNodePosi<T> p) const;

    ListNodePosi<T> search(T const&e) const
    {
        return search(e, _size, trailer);
    }
    ListNodePosi<T> search(T const& e, int n, ListNodePosi<T> p) const;

    ListNodePosi<T> selectMax(ListNodePosi<T> p, int n);//在p及其n-1个后继中选出最大者
    ListNodePosi<T> selectMax() { return selectMax(header->succ, _size); }

    //可写访问接口
    ListNodePosi<T> insertAsFrist(T const& e) {
        //将e当作首节点插入
        return insert(header, e);
    };
    ListNodePosi<T> insertAsLast(T const& e) {
        //将e当作末节点插入
        return insert(e, trailer);
    };

    ListNodePosi<T> insert(ListNodePosi<T> p, T const& e)
    { //将e当作p的后继插入
        _size++; return p->insertAsSucc(e);
    };
    ListNodePosi<T> insert(T const& e, ListNodePosi<T> p) {
        //将e当作p的前继插入
        _size++; return p->insertAsPred(e);
    };

    T remove(ListNodePosi<T> p);//删除合法位置p的节点,返回被删除的节点数据

    //遍历
    void getInfo() {
        cout << "节点个数 " << _size << endl;
        ListNodePosi<T> temp = first();
        while (temp != trailer) {
            cout << temp->data << " ";
            temp = temp->succ;
        }
        cout << endl;
    }
};

template<typename T>
void List<T>::init() {
    header = new ListNode<T>;
    trailer = new ListNode<T>;

    header->succ = trailer; header->pred = nullptr;
    trailer->pred = header; trailer->succ = nullptr;

    _size = 0;
}

template<typename T>
int List<T>::clear() {
    int oldSize = _size;
    while (0 < _size) remove(header->succ);
    return oldSize;
};

template<typename T>
T List<T>::remove(ListNodePosi<T> p) {
    T tempData = p->data;
    p->succ->pred = p->pred;
    p->pred->succ = p->succ;
    delete p;
    _size--;
    return tempData;
};

template<typename T>
List<T>::~List() {
    clear();
    delete header; delete trailer;
};

template<typename T>
void List<T>::copyNode(ListNodePosi<T> p, int a) {
    init();
    while (a--) { insertAsLast(p->data); p = p->succ; }
};

template<typename T>
List<T>::List(List<T> const& L, Rank r, int n) {
    ListNodePosi<T> p = L.first();
    while (0 < r--) p = p->succ;
    copyNode(p, n);
};

template<typename T>
List<T>::List(List<T> const& L) {
    copyNode(L.first(), L._size);
};

template<typename T>
List<T>::List(ListNodePosi<T> p, int n) {
    //复制列表中自位置p起的n项
    copyNode(p, n);
};

template<typename T>
List<T>::List(T* A, int n) {
    init();
    for (int i = 0; i < n; i++)
        insertAsLast(A[i]);
};

栈应用

进制转换

没啥说的,就是digit数组比较巧妙。避免了一个个转换的问题。

//n非负数,十进制转换为base进制,base<16
void convert(Stack<char>& s, __int64 n, int base) {
    
    char digit[] = {'0','1','2','3','4','5','6','7','8','9'
    ,'A','B','C','D','E'};
    if (n == 0) {
        s.push(digit[0]); return;
    }
    while (n > 0) {
        s.push(digit[n % base]);
        n /= base;
    }

}

括号匹配

用于多个对应的括号交叉混乱,看他合不合法。html的<p> <\p>之类的也是用这个方法。

//括号匹配,{ [ (
bool paren(const char exp[], int lo, int hi) {
    Stack<char> S;
    for (; lo < hi; lo++) {
        if ((exp[lo] == '(') || (exp[lo] == '[') || (exp[lo] == '{'))
            S.push(exp[lo]);
        else if (S.empty())
            return false;
        else if (exp[lo] == ')')
        {
            if (S.top() == '(')
                S.pop();
            else
                return false;
        }
        else if (exp[lo] == ']')
        {
            if (S.top() != '[')
                return false;
            else
                S.pop();
        }
        else if (exp[lo] == '}')
        {
            if (S.top() != '{')
                return false;
            else
                S.pop();
        }
    }
    return S.empty();
}

中缀表达式求值

运算的时候,最后的两个运算数,要注意运算顺序,谁除谁,后出来的是被减数,先出来的是减数字。

精华还是在符号优先级的表。

#define N_OPTR 9

typedef enum
{
    ADD, SUB, MUL, DIV, POW, FAC, L_P, R_P, EOE,
} Operator; //运算符集合

const char pri[N_OPTR][N_OPTR] =
{ //运算符优先等级 [栈顶] [当前]
   /*              |-------------------- 当 前 运 算 符 --------------------| */
   /*              +      -      *      /      ^      !      (      )      \0 */
    /* --  + */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
    /* |   - */    '>',   '>',   '<',   '<',   '<',   '<',   '<',   '>',   '>',
    /* 栈  * */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
    /* 顶  / */    '>',   '>',   '>',   '>',   '<',   '<',   '<',   '>',   '>',
    /* 运  ^ */    '>',   '>',   '>',   '>',   '>',   '<',   '<',   '>',   '>',
    /* 算  ! */    '>',   '>',   '>',   '>',   '>',   '>',   ' ',   '>',   '>',
    /* 符  ( */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   '=',   ' ',
    /* |   ) */    ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',   ' ',
    /* -- \0 */    '<',   '<',   '<',   '<',   '<',   '<',   '<',   ' ',   '='
};

Operator optr2rank(char op)
{ //由运算符转译出编号
    switch (op)
    {
    case '+':
    {
        return ADD; //加
    }
    case '-':
    {
        return SUB; //减
    }
    case '*':
    {
        return MUL; //乘
    }
    case '/':
    {
        return DIV; //除
    }
    case '^':
    {
        return POW; //乘方
    }
    case '!':
    {
        return FAC; //阶乘
    }
    case '(':
    {
        return L_P; //左括号
    }
    case ')':
    {
        return R_P; //右括号
    }
    case '\0':
    {
        return EOE; //起始符与终止符
    }
    default:
    {
        exit(-1); //未知运算符
    }
    }
}

//中缀表达式求值
//读数
void readNumber(Stack<double>& optn, char*& p) {
    bool isNegitive = false;
    if (p[0] == '-') {
        p++; isNegitive = true;
    }
    double result = 0;
    //整数部分
    while (isdigit(*p)) {
        result = result * 10 + (int)(*(p++) - '0');
    }

    //小数部分
    double wei = 0.1;
    if ((*p) == '.') {
        p++;
        while (isdigit(*p)) {
            result +=(*(p++) - '0')*wei;
            wei *= 0.1;
        }
    }
    if (isNegitive) 
        result *= -1;
    optn.push(result);
    
}

//阶乘
int fac(int n) {
    int res = 1;
    while (n--)
        res *= (n + 1);
    return res;
}

//乘方
int fac(int a, int b) {
    int res = 1;
    while (b--) {
        res *= a;
    }
    return res;
}

//运算符优先级
char getRank(char a,char b) {
    return pri[optr2rank(a)][optr2rank(b)];
}

//计算
double calcu(double num1, char optr, double num2) {
    if (optr == '+') return num1 + num2;
    else if (optr == '-') return num1 - num2;
    else if (optr == '*') return num1 * num2;
    else if (optr == '/') return num1 / num2;
    else if (optr == '^') return fac(num1, num2);
    else return 0;
}

//运算主函数
double calcu(char *p) {
    Stack<char> optr;
    Stack<double> optn;
    optr.push('\0');
    while (!optr.empty()) {
        if (isdigit(*p))
            readNumber(optn, p);
        else {
            switch (getRank(optr.top(),*p))
            {
            case '<': 
            {
                optr.push(*p); p++; 
                break;
            }
            case '=': 
            {
                optr.pop(); p++; //脱括号并接收下一个字符
                break;
            }
            case '>':{
                char opt = optr.pop();
                if (opt == '!') {
                    double nums1 = optn.pop();
                    optn.push(fac(nums1));
                }
                else {
                    double nums2 = optn.pop();
                    double nums1 = optn.pop();
                    optn.push(calcu(nums1, opt, nums2));
                }
                break;
            }
            }
        }
    }
    return optn.top();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值