算法思想总结:栈

news2024/9/29 19:21:19

一、栈的经典应用:波兰表达式与逆波兰表达式

          我们平时看到的 1+2*(3-4*5)+6/7 叫做中缀表达式,平时我们习惯用这个计算的原因是我们可以整体地去看到这个表达式并且清楚地知道各个运算符的优先级,但是计算机并不一定知道,因为他总是从前往后去遍历这个表达式。如上面这个例子,当按照计算机的逻辑去扫描了1+2的时候,并不敢直接去进行运算,因为可能后面存在一个优先级更高的操作符会优先进行计算。甚至有些时候还会出现括号这一种可以改变操作符优先级的符号!!所以这个时候,为了能够解决这个问题,就有了波兰表达式(前缀表达式)和逆波兰表达式(后缀表达式)。

     前缀表达式:操作符+操作数+操作数

     中缀表达式:操作数+操作符+操作数

     后缀表达式:操作数+操作数+操作符

1.1 后缀表达式转中缀表达式

 1.2 中缀表达式转后缀表达式

 二、逆波兰表达式求值

. - 力扣(LeetCode)

class Solution {
public:
    int evalRPN(vector<string>& tokens) 
    {
      stack<int> st;//栈帮助我们计算
      for(auto&s:tokens) //遍历字符串
      {
        if(s=="+"||s=="-"||s=="*"||s=="/")//如果是操作符的话,取栈顶两个元素计算
        {
           //先取右操作数,再取左操作数
           int right=st.top(); st.pop();
           int left=st.top();st.pop();
           //因为可能会有不同的情况,所以要用一个swich去计算
           switch(s[0])
           {
            case '+':
              st.push(left+right);
              break;
            case '-':
              st.push(left-right);
              break;
            case '*': 
              st.push(left*right);
              break;
            case '/': 
               st.push(left/right);
               break;
           }
        }
        else st.push(stoi(s));如果不是操作符的话,利用stoi将字符串转化成数字并入栈 
      }
      return st.top();
    }
};

三、基本计算器II

. - 力扣(LeetCode)

class Solution {
public:
    int calculate(string s) 
    {
      vector<int> v;
      char op='+';
      int i=0,n=s.size();
      while(i<n)
      {
        if(s[i]==' ') ++i;
        else if(isdigit(s[i]))
        {
            int temp=0;//先取出这个数字
            while(i<n&&isdigit(s[i]))  temp=temp*10+(s[i++]-'0');
            //这时候要根据当前op的情况去判断怎么操作
            switch(op)
            {
              case '+':v.push_back(temp);break;
              case '-':v.push_back(-temp);break;
              case '*':v.back()*=temp;break;
              case '/':v.back()/=temp;break;
            }
        }
        else op=s[i++];//是操作符就直接改掉op
      }
      return accumulate(v.begin(),v.end(),0);
    }
};

四、基本计算器I 

. - 力扣(LeetCode)

class Solution {
public:
    void calc(stack<int> &numst, stack<char> &ops)
    {
                int right=numst.top();numst.pop();
                int left=numst.top();numst.pop();
                char op=ops.top();ops.pop();
                numst.push(op=='+'?left+right:left-right);//根据op去计算
    }

    void replace(string&s)
    {
        //去掉空格
        int pos=s.find(" ");
        while(pos!=-1) 
        {
            s.erase(pos,1);
            pos=s.find(" ");
        }
    }
   
    int calculate(string s)
    {
        //利用双栈
        stack<int> numst;//存放所有数字
        //防止第一个数为负数
        numst.push(0);//防止第一个数是负数
        stack<char> ops;//存放所有运算符
        replace(s);
        int n=s.size();int i=0;
        while(i<n)
        {
            if(s[i]=='(')  ops.push(s[i++]);  //如果是左括号 直接压栈。
            else if(s[i]==')')  //如果是右括号,就计算到左括号为止
            {
               while(ops.top()!='(')  calc(numst,ops);  //还没遍历到左括号的时候
                     //循环结束说明遇到(了 此时跳过即可
                   ops.pop();//弹出左括号
                   ++i;//去下一个位置
            }
            else if(isdigit(s[i]))//遇到数字的时候
            {
                int temp=0;
                while(i<n&&isdigit(s[i])) temp=temp*10+(s[i++]-'0');
                numst.push(temp);
            }
            else //此时遇到操作符了
            {  
                if(i>0&&s[i]=='-'&&s[i-1]=='(') numst.push(0);//应对括号后面带负数的情况
                while(!ops.empty()&& ops.top() != '(')//放入之前先把能算的给算了
                        calc(numst, ops);
                ops.push(s[i++]);//操作符入栈
            }
        }
        //最后要将栈中的所有的都计算一便
        while(!ops.empty())   calc(numst,ops);
        return numst.top();//最后剩下的就是最终结果
    }
};

五、有效的括号

. - 力扣(LeetCode)

class Solution {
public:
    bool isValid(string s)
    {
      //用一个栈来模拟 
      stack<char> st;
      for(auto&ch:s)
      {
        if(ch=='('||ch=='{'||ch=='[') st.push(ch);//遇到左括号肯定是无脑入栈的
        else //此时肯定遇到了右括号 
        {
            //有两种情况,一种是右括号比左括号多,此时栈可能为空,就肯定不符合了
            if(st.empty()) return false;
            //还有一种情况是前面的对不上
            else if(ch==')'&&st.top()!='(' ||ch=='}'&&st.top()!='{'||ch==']'&&st.top()!='[') return false;
            else st.pop();
        }
      }
      return st.empty();//可能左括号比右括号多,导致最后栈里面还有剩下
    }
};

六、删除字符串中所有相邻重复项

. - 力扣(LeetCode)

class Solution {
public:
    string removeDuplicates(string s) 
    {
        string ret;
        for(auto&ch:s)
        {
            if(ret.size()&&ret.back()==ch) ret.pop_back();
            else ret.push_back(ch);
        }
        return ret;
    }
};

七、比较含退格的字符串

. - 力扣(LeetCode)

class Solution {
public:
    bool backspaceCompare(string s, string t) 
    {
       //没遇到# 就入栈,遇到#就出栈
       return stringchange(s)==stringchange(t);
    }
    string stringchange(string&s)
    {
        string ret;
        for(auto &ch:s)
        {
            if(ch!='#') ret.push_back(ch);
            else if(ret.size()) ret.pop_back();
        }
        return ret;
    }
};

八、字符串解码

. - 力扣(LeetCode)

该题也是利用到基本计算器的解题思想

class Solution {
public:
    string decodeString(string s)
    {
     stack<int> numst;//数字栈
     stack<string> strst;//字符串栈
     strst.push("");//先插入一个空字符串 防止越界访问
     int i=0,n=s.size();
     while(i<n)
     {
        if(isdigit(s[i])) //遇到数字,提取出来放到字符串栈中
        {
          int temp=0;
          while(isdigit(s[i])) temp=temp*10+(s[i++]-'0');
          numst.push(temp);
        }
        else if(s[i]=='[')//遇到[将后面的字符串提取出来放入字符串栈中
        {
            ++i;//先跳过这个括号
            string str;
           while(islower(s[i])) str+=s[i++];
           strst.push(str);
        }
        else if(s[i]==']')//遇到]就提取栈顶元素进行计算
        {
            int k=numst.top();numst.pop();
            string str=strst.top();strst.pop();
            for(int j=0;j<k;++j) strst.top()+=str;
            ++i;//跳过这个右括号
        }
        else //遇到单独的字符,直接加进去
            strst.top()+=s[i++];
     }    
     return strst.top();
    }
};

九、最小栈

. - 力扣(LeetCode)

 策略3解题:

class MinStack {
public:
    MinStack() {

    }
    
    void push(int val) {
         st.push(val);
         //如果当前栈为空,或者是当前的数比栈顶元素小或者相等,就入minst
         if(minst.empty()||minst.top()>=val) minst.push(val);
    }
    
    void pop() {
         //如果当前数和minst的栈顶元素相等,就得出
         if(minst.top()==st.top()) minst.pop();
          st.pop();
    }
    
    int top() {
      return st.top();
    }
    
    int getMin() {
       return minst.top();
    }
    private:
        stack<int> st;
        stack<int> minst;
    };

策略4解题:存键值对

class MinStack {
public:
    MinStack() {

    }
    
    void push(int val) {
         st.push(val);
         //如果当前栈为空,或者是当前的数比栈顶元素小或者相等,就入minst
         if(minst.empty()||minst.top().first>val) minst.push(pair(val,1));
         else if(minst.top().first==val) ++minst.top().second;
    }
    
    void pop() {
         if(minst.top().first==st.top()) 
         {
            if(minst.top().second==1) minst.pop();
            else --minst.top().second;
         }
          st.pop();
    }
    
    int top() {
      return st.top();
    }
    
    int getMin() {
       return minst.top().first;
    }
    private:
        stack<int> st;
        stack<pair<int,int>> minst;//第一个代表最小值,第二个代表其数量
    };

十、验证栈序列

. - 力扣(LeetCode)

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
       stack<int> st;
        int popi=0;
       for(auto&num:pushed)
        {
            st.push(num);
            while(!st.empty()&&st.top()==popped[popi])//可能会连续出多个
                {
                     st.pop();
                    ++popi;
                }
        }
                  //return popi==popV.size();
                  return st.empty();
    }
};

十一、1-n所有可能的出栈序列

如果入栈序列是1-n 将所有可能的出栈序列存储起来并返回。

//尝试输出所有出栈序列
vector<vector<int>> ret;//记录所以出栈序列
int n;//记录入栈范围
void dfs(int i, vector<int> push, vector<int> pop) //深搜+回溯
{
	if (i == n + 1)
	{
		if (pop.size() == n)
		{
			ret.push_back(pop);
		}
		return;
	}
	//入栈
	push.push_back(i);
	//可以选择出栈,或者不出栈
	//选择不出栈
	dfs(i + 1, push, pop);
	//选择出栈
	while (!push.empty())
	{
		pop.push_back(push.back());
		push.pop_back();
		dfs(i + 1, push, pop);//用形参去记录路径
	}
}
vector<vector<int>> poporder(int _n)
{
	n = _n;
	dfs(1, {}, {});
	return ret;
}

我们来测试一下: 

void test()
{
	vector<vector<int>> ret = poporder(5);
	for (int i = 0; i < ret.size(); ++i)
	{
		for (int j = 0; j < ret[i].size(); ++j)
			cout << ret[i][j] << " ";
		cout << endl;
	}
	cout << "入栈序列为";
	for (int i = 1; i <= n; ++i) cout << i;
	cout << "的出栈序列一共有" << ret.size() << "种" << endl;;
}

 十二、利用栈实现基本计算器

目标:实现一个基本计算器,能够满足以下条件的运算:

  1. 操作数:支持正数、负数、多位数计算
  2. 操作符:支持( ) + - * / % ^ 这些操作符

设计思路来源:中缀表达式和后缀表达式

具体的设计思路:

  1. 所需要的数据结构——双栈+哈希表(设为全局变量)。其中一个存储整型的栈帮助我们存储操作数,另一个存储字符类型的栈帮助我们存储操作符,然后哈希表帮我们确立操作符的优先级。
  2. + -的映射关系为1,* / %的映射关系为2,^的映射关系为3,按照上述方式存进哈希表来映射操作符优先级。然后对于左括号和右括号,我们进行特殊处理。
  3. 因为我们输入的是字符串,所以有些时候需要用空格分割操作符和操作数,所以我们在计算前的第一步就是封装一个replace函数来帮助我们删除字符串中的所用空格。
  4. 封装一个calc函数,帮助我们在满足计算条件的时候,取出数字栈的头两个元素分别作为右操作数和左操作数,再取出字符栈的栈顶操作符进行计算,用一个swtich语句根据不同的操作符类型执行不同的运算逻辑
  5. 进行分类讨论:
  1. 如果遇到(,无脑进栈
  2. 如果遇到 ),不断进行calc直到遇到( ,并将(弹出
  3. 如果遇到数字,因为要实现的是多位数的计算,所以可能后面的数字是挨着连在一起的,此时我们要想将该数提取出来,如果下一位也是数字,就将当前的数*10+下一个数字,当不再是数字的时候,将提取出来的数字入数字栈。
  4. 如果遇到操作符,首先要处理一个特殊情况就是,如果当前操作符是- 并且前一个操作符时( 说明该-表示的是负数而不是减,所以为了运算的合理性,我们要在数字中压个0进去。  然后我们的新操作符要跟栈顶的操作符进行比较,如果运算的优先级较低或相等,就得将栈顶的操作符弹出来进行计算,即进行calc,不断重复该过程,直到新加入的操作符优先级比栈顶元素高,此时再将新操作符入栈
  5. 细节处理:第一个数可能是负数,所以我们也要按照(4)中的逻辑一样,再数字栈上先压个0进去。
  6. 最后当整个字符串遍历结束之后,我们将栈中剩余的操作数和操作符拿出来运算,最后留在数字栈顶的元素。就是我们的最终结果。
  7. 该计算器的小缺陷:(1)不支持浮点数(2)整型除不尽会舍去。
using namespace std;
unordered_map<char, int> map{{'+',1},{'-',1} ,{'*',2} ,{'/',2} ,{'%',2} ,{'^',3}}; //建立哈希映射,建立各操作符的优先级。
stack<int> nums;//创建一个数字栈,存储操作数信息
stack<char> ops;//创建一个字符栈,存储操作数信息
//对于左括号,我们直接入栈,等待右括号的匹配
//一旦遇到右括号,就需要计算()内的结果,直到遇到左括号然后弹出
//计算器
void calc()
{
    if (nums.size() < 2 || ops.empty())
    {
        cout << "表达式有误" << endl;
        return;//少于两个操作数或没有操作符,说明输入的表达式有误
    }
    //先取右操作数,再取左操作数,根据操作符进行运算
    int right = nums.top(); nums.pop();
    int left = nums.top(); nums.pop();
    char op = ops.top(); ops.pop();
    switch (op)
    {
    case '+':nums.push(left + right); break;
    case '-':nums.push(left - right); break;
    case '*':nums.push(left * right); break;
    case '/':nums.push(left / right); break;
    case '%':nums.push(left % right); break;
    case '^':nums.push((int)pow(left, right)); break;
    default:cout << "操作符有误" << endl; break;//如果都不符合,就是操作符有误
    }
}
void replace(string& s) //删除字符串中所有空格
{
    int index = 0;
    if (!s.empty())
    {
        while ((index = s.find(' ', index)) != string::npos)
        {
            s.erase(index, 1);
        }
    }
}
//可以计算整型(正负数均可,也可以是多位数)    有关()、+、-、*、/、%、^的运算      
//小缺陷:1、不支持小数   2、因为是整型,/除不尽小数会被省去
int calculate(string s)//基本计算器的实现
{
    replace(s);//先去掉空格 方便我们计算
    int i = 0, n = s.size();//用来遍历字符串
    nums.push(0);//先补个0,目的是防止第一个数是负数
    while (i < n)
    {
      //如果遇到( 直接压栈即可
        if (s[i] == '(') ops.push(s[i++]);
      //如果遇到右括号,将一直到(的结果进行计算
        else if (s[i] == ')')
        {
            while (ops.top() != '(') calc();
            //此时遇到左括号,弹出左括号并++
            ops.pop();
            ++i;
        }
        //如果遇到数字,将数字提出出来
        else if (isdigit(s[i]))
        {
           //将数字提取出来放到nums中
            int temp = 0;
            while (i < n && isdigit(s[i])) temp = temp * 10 + (s[i++] - '0');
            nums.push(temp);
        }
        //如果遇到操作符
        else
        {
           //如果是(-的情况,补0,保证运算合理
            if (i > 0 && s[i] == '-' && s[i - 1] == '(') nums.push(0);
            //在放入这个操作符之前,把能算的给算了
            while (!ops.empty() && ops.top() != '(')//放入之前先把能算的给算了
            {
                char prev = ops.top();
                if (map[prev] >= map[s[i]])  calc();//如果我比前面的运算符优先级低或者相等,就将前面运算符弹出来计算。
                else break;
            }
            //然后将新的操作符入栈
            ops.push(s[i++]);
        }
    }
    //整个过程遍历结束后,将栈中的剩下的进行计算
    while (!ops.empty()) calc();
    return nums.top();//此时栈顶留下来的就是最终结果
}

十三、利用栈实现十进制转任意进制 

stack<int> st;//帮助我们存储进制数
string basechage(int n, int x) 
{
    string ret;
    if (x < 2 && x>36) { cout << "不存在" << x << "进制数" << endl; return ret; }
    while (n) //当n变成0的时候
    {
        st.push(n % x);
        n/=x;
    }
    //此时栈中存储的就是 最终结果 
    while (!st.empty())
    {
        int top = st.top();
        if ( top>=0 && top <= 9) //如果是0-9,直接插入
            ret.push_back(top + '0');
        else //此时不是1-9,要用字母来替代
            ret.push_back(top + 55);
        st.pop();
    }
    return ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1614556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript之模块化规范详解

文章的更新路线&#xff1a;JavaScript基础知识-Vue2基础知识-Vue3基础知识-TypeScript基础知识-网络基础知识-浏览器基础知识-项目优化知识-项目实战经验-前端温习题&#xff08;HTML基础知识和CSS基础知识已经更新完毕&#xff09; 正文 CommonJS、UMD、CMD和ES6是不同的模块…

详解爬虫基本知识及入门案列(爬取豆瓣电影《热辣滚烫》的短评 详细讲解代码实现)

目录 前言什么是爬虫&#xff1f; 爬虫与反爬虫基础知识 一、网页基础知识 二、网络传输协议 HTTP&#xff08;HyperText Transfer Protocol&#xff09;和HTTPS&#xff08;HTTP Secure&#xff09;请求过程的原理&#xff1f; 三、Session和Cookies Session Cookies Session与…

核桃派全志H616实现VNC远程桌面教程

VNC远程桌面 核桃派预装了VNC服务器&#xff0c;VNC适应于局域网&#xff08;通常指同一个路由器网络下&#xff09;桌面登录。使用该服务前先确保核桃派已经通过以太网或无线WiFi连接到路由器。 使用核桃派桌面系统的时候由于要配置各类信息和联网&#xff0c;可以使用HDMI显…

【C语言】每日一题,快速提升(5)!

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 目录 1. strlen函数 2. strcpy函数 3. strcat函数 题目&#xff1a;模拟实现 strlen--strcpy--strcat--三个函数 1. strlen函数 字符串计算 #include <stdio.h…

硕士博士学位论文格式检查规范

包含标题、摘要、英文缩写、关键词、公式、表格、图片、参考文献&#xff0c;只能说太强了 学位论文检查三十六策点击蓝字 关注我们 写在前面 同学们撰写学位论文时&#xff0c;常常犯一些错误&#xff0c;既有格式错误&#xff0c;也有内容错误。本文列举36https://mp.weixin.…

【python】如何通过python来发送短信

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

SFP、SFP+、SFP28 与 QSFP28 收发器之间的差异:兼容性和性能

近年来&#xff0c;网络技术发展迅速&#xff0c;因此&#xff0c;计算专业人员面临着越来越令人困惑的术语和缩写词。 管理数据中心时必须了解的一个关键领域是收发器&#xff0c;特别是 SFP (1550nm/1310nm)、SFP (850nm) 和 QSFP28 (4x25G) 之间的差异。 这些型号在兼容性方…

【热门话题】常用经典目标检测算法概述

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 常用经典目标检测算法概述1. 滑动窗口与特征提取2. Region-based方法R-CNN系列M…

【日志】CSDN-AI助手升级日志

CSDN-AI助手升级日志 2023/04/05上线 支持点赞、收藏回访 关注回访&#xff08;对方至少有一条博客的记录&#xff09; 评论回访 私信检测到群发消息自动三连 OR 通过私信指令三连触发 bug优化 优化检测模式&#xff0c;防止出现多触发情况 为了防止操作额度不够&#xff0c…

Java面试八股之简述Servlet体系结构

简述Servlet体系结构 Servlet是Java Web开发中的核心组件&#xff0c;用于接收和响应HTTP请求&#xff0c;生成动态内容。它具有平台无关性、协议无关性和动态内容生成能力&#xff0c;遵循明确的生命周期。尽管现代Web开发中更多使用高级框架&#xff0c;但Servlet作为基础&a…

[笔试训练](二)

004 牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目&#xff1a; 题解&#xff1a; 使用向上取整函数ceil()&#xff0c;&#xff08;记得添加头文件#include<cmath>&#xff09; #include <iostream> #include <cmath> using namespace std;int main(…

基于SpringBoot+Vue的企业资产管理系统设计与实现

1、系统演示视频&#xff08;演示视频&#xff09; 2、需要请联系

Ceph 分布式文件系统 搭建及使用

一、Ceph 介绍 在当今数据爆炸式增长的时代&#xff0c;企业对于可靠、可扩展的存储解决方案的需求日益迫切。Ceph 作为一种开源的、可伸缩的分布式存储解决方案&#xff0c;正逐渐成为企业级存储领域的热门选择。Ceph是一种由Radicalbit公司开发的开源分布式存储系统&#xf…

Visual Studio 2022 Professional、Enterprise安装教程

Visual Studio 2022 Professional、Enterprise安装教程 下载安装包安装 我是电脑已经有VS2019&#xff0c;现在加装一个VS2022。 下载安装包 首先下载安装包&#xff0c;进入官网进行下载&#xff0c;VS官网下载地址。 进入之后&#xff0c;会显示如下界面&#xff0c;选择Pro…

chrome插件 脚本 使用和推荐

chrome插件使用 在极简插件中可以进行下载并进行安装, 内部有安装教程在极简插件中搜索"油猴",下载一个油猴插件,并安装,可以用于下载很多的用户脚本用户脚本下载地址Greasy Fork,里面有很多实用的用户脚本供下载,并在油猴中进行管理 推荐的插件 Tampermonkey 篡改…

Linux进阶篇:centos7搭建jdk环境

Linux服务搭建篇&#xff1a;centos7搭建jdk环境 本文主要介绍的是如何是Linux环境下安装JDK的&#xff0c;关于jdk的概念就不做赘述了&#xff0c;相信大家都有所耳闻了&#xff0c;Linux环境下&#xff0c;很多时候也离不开Java的&#xff0c;下面笔者就和大家一起分享如何jd…

都2024年了,你还不知道git worktree么?

三年前 python 大佬吉多范罗苏姆(为 Python 程序设计语言的最初设计者及主要架构师)才知道 git worktree &#xff0c;我现在才知道&#xff0c;我觉得没啥丢人的。 应用场景 如果你正在 feature 的分支中开发新功能&#xff0c;线上版本紧急错误又需要你基于 master 做修复。…

DFS和回溯专题:组合总和

DFS和回溯专题&#xff1a;组合总和 题目链接: 39.组合总和 参考题解&#xff1a;代码随想录 题目描述 代码纯享版 class Solution {public List<List<Integer>> list_all new ArrayList();public List<Integer> list new ArrayList();public List<…

linux服务器和RAID磁盘阵列

1、服务器 &#xff08;1&#xff09;服务器分类 机架式居多 塔式 刀片式 机柜式 机架式 机架式服务器是一种服务器的机箱形式&#xff0c;它被设计为在服务器机架或机柜中安装。机架式服务器通常具有标准的19英寸宽度&#xff0c;并且可以根据服务器的高度进行划分&#xff0…

gcc/g++编译器

之前学习的vim为linux中编写程序的编写器&#xff0c;但是程序想要编译执行就还需要c语言的编译器gcc 程序翻译的过程 首先我们来了解一下程序编译语言的诞生历程 首先计算机只知道二进制&#xff0c;所以人们开始是用二进制编码&#xff0c;然后又用二进制编码写了一个汇编语…