欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器

 更新時(shí)間:2023年10月30日 09:08:15   作者:Keiichi  
這篇文章主要為大家詳細(xì)介紹了如何基于Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下

計(jì)算器實(shí)現(xiàn)原理

我們平時(shí)見(jiàn)到的算式都是這種類型 1+(2+3)*4,這種類型的表達(dá)式也被稱為中綴表達(dá)式,我們很容易理解它的運(yùn)算順序。但是計(jì)算機(jī)卻無(wú)法理解這個(gè)式子

因此我們需要將其轉(zhuǎn)化為便于計(jì)算機(jī)理解的式子,轉(zhuǎn)化為后綴表達(dá)式或者前綴表達(dá)式(其實(shí)都差不多)。在這里我們以后綴表達(dá)式為例子。

中綴表達(dá)式如何轉(zhuǎn)化為后綴表達(dá)式

1+(2+3)*4的后綴表達(dá)式為123+4*+,前者轉(zhuǎn)換成后者的過(guò)程需要利用到棧和隊(duì)列這兩個(gè)數(shù)據(jù)結(jié)構(gòu),不太清楚可以看看:棧和隊(duì)列詳解

首先我們需要一個(gè)棧和隊(duì)列

然后從左到右依次根據(jù)一定規(guī)則判斷是否入棧

入棧規(guī)則如下:

  • 數(shù)字直接入隊(duì)列
  • 若是運(yùn)算符,則判斷其與棧頂符號(hào)的優(yōu)先級(jí),優(yōu)先級(jí)低于或等于棧頂符號(hào),棧內(nèi)元素不斷出棧,進(jìn)入隊(duì)列,直到棧空或者碰見(jiàn)左括號(hào)為止
  • 若是左括號(hào)則直接入棧
  • 若是右括號(hào)則棧內(nèi)所有元素出棧,進(jìn)入隊(duì)列,直到遇見(jiàn)與之匹配的左括號(hào)
  • 最后棧內(nèi)所有元素按順序入列

現(xiàn)在我們開始進(jìn)行變換

最后得到我們的結(jié)果123+4*+中綴就成功轉(zhuǎn)化成后綴表達(dá)式了

計(jì)算機(jī)是如何理解后綴表達(dá)式的

計(jì)算機(jī)會(huì)將之前放在隊(duì)列里的元素按照先進(jìn)先出(FIFO)的規(guī)則,將元素彈出進(jìn)行判斷
如果元素為數(shù)字,則直接入棧,若元素為運(yùn)算符,則從棧中彈出兩個(gè)數(shù)字進(jìn)行運(yùn)算,再將運(yùn)算結(jié)果放入棧中
當(dāng)隊(duì)列全部元素取出后,最后棧中剩下的唯一一個(gè)元素就是我們要找的結(jié)果了

在GO中的實(shí)現(xiàn)

首先我們需要?jiǎng)?chuàng)造出我們的工具:棧和隊(duì)列

實(shí)現(xiàn)棧

type Stack struct {      //定義棧
   elements []interface{}  //因?yàn)閮?chǔ)存的元素是空接口類型,所以之后要注意類型斷言和類型轉(zhuǎn)化
}

func NewStack() *Stack {   //返回一個(gè)棧
   return &Stack{}
}

func (s *Stack) empty() bool {  //判斷棧是否為空
   return len(s.elements) == 0
}

func (s *Stack) push(x interface{}) { //將元素入棧
   s.elements = append(s.elements, x)
}

func (s *Stack) pop() (interface{}, error) {  //將棧頂元素記錄并彈出
   if s.empty() {
      return nil, errors.New("empty stack")
   }
   ret := s.elements[len(s.elements)-1]
   s.elements = s.elements[:len(s.elements)-1]
   return ret, nil
}

func (s *Stack) top() (interface{}, error) {  //只查詢棧頂元素,不彈出
   if s.empty() {
      return nil, errors.New("empty stack")
   }
   return s.elements[len(s.elements)-1], nil
}

實(shí)現(xiàn)隊(duì)列

type Queue struct {       //定義隊(duì)列
   elements []interface{}
}

func NewQueue() *Queue {   //返回一個(gè)隊(duì)列
   return &Queue{}
}

func (q *Queue) empty() bool {  //判斷隊(duì)列是否為空
   return len(q.elements) == 0
}

func (q *Queue) push(x interface{}) {   //將元素壓入隊(duì)列
   q.elements = append(q.elements, x)
}

func (q *Queue) pop() (interface{}, error) {  //將最先進(jìn)入的元素記錄并彈出
   if q.empty() {
      return nil, errors.New("empty queue")
   }

   if len(q.elements) == 1 {

      ret := q.elements[0]
      r := ret.(string)
      println(r)
      q.elements = q.elements[0:0]
      return ret, nil
   } else {
      ret := q.elements[0]
      q.elements = q.elements[1 : len(q.elements)-1]
      return ret, nil
   }
}

中綴轉(zhuǎn)后綴實(shí)現(xiàn)

按照先前的規(guī)則,靈活運(yùn)用判斷語(yǔ)句實(shí)現(xiàn)中綴到后綴表達(dá)式的實(shí)現(xiàn)

func Transform(S *Stack, Q *Queue, input string) error {
   temp := ""
   for i := 0; i < len(input); i++ {
      switch string(input[i]) {
      case "+":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }
         if S.empty() { //如果棧為空,直接入棧
            S.push(string(input[i]))
         } else { // 如果棧不為空
            m, _ := S.top()
            if m.(string) == "(" { //前一個(gè)是左括號(hào)直接入棧
               S.push(string(input[i]))
            } else { //否則全出
               for {
                  t, _ := S.pop()
                  Q.push(t.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "-":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }
         if S.empty() { //如果棧為空,直接入棧
            S.push(string(input[i]))
         } else { // 如果棧不為空
            m, _ := S.top()
            if m.(string) == "(" { //前一個(gè)是左括號(hào)直接入棧
               S.push(string(input[i]))
            } else { //否則全出
               for {
                  t, _ := S.pop()
                  Q.push(t.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "*":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }

         if S.empty() { //如果棧為空直接入棧
            S.push(string(input[i]))
         } else { //反之,將棧內(nèi)元素彈出,放入隊(duì)列
            t, _ := S.top()
            if t.(string) == "+" || t.(string) == "-" || t.(string) == "(" { //棧頂為加減號(hào)或左括號(hào),直接入棧
               S.push(string(input[i]))
            } else {
               for {
                  j, _ := S.pop()
                  Q.push(j.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" || a.(string) == "+" || a.(string) == "-" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "/":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }

         if S.empty() { //如果棧為空直接入棧
            S.push(string(input[i]))
         } else { //反之,將棧內(nèi)元素彈出,放入隊(duì)列
            t, _ := S.top()
            if t.(string) == "+" || t.(string) == "-" || t.(string) == "(" { //棧頂為加減號(hào)或左括號(hào),直接入棧
               S.push(string(input[i]))
            } else {
               for {
                  j, _ := S.pop()
                  Q.push(j.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" || a.(string) == "+" || a.(string) == "-" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "(":
         //別管,直接入棧
         S.push(string(input[i]))
      case ")":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }
         for {
            j, _ := S.pop()
            Q.push(j.(string))
            a, _ := S.top()
            if a.(string) == "(" { //直到碰到左括號(hào)為止,然后帶走左括號(hào)
               _, _ = S.pop()
               break
            }
         }
      default:
         if '0' <= input[i] && input[i] <= '9' {
            temp += string(input[i])
         } else {

            return errors.New("valid input")
         }
      }
   }
   //若還有數(shù)字沒(méi)有入隊(duì)列就入
   if temp != "" {
      Q.push(temp)
   }
   //若棧還有運(yùn)算符就出棧
   for {
      if S.empty() {
         break
      }
      t, _ := S.pop()
      Q.push(t.(string))
   }
   return nil
}

計(jì)算過(guò)程的實(shí)現(xiàn)

邏輯十分簡(jiǎn)單,主要注意的是類型間的轉(zhuǎn)化,要從空接口類型斷言為string類型,再將string類型轉(zhuǎn)化為int類型進(jìn)行計(jì)算,使用float類型也可以實(shí)現(xiàn)小數(shù)計(jì)算,可以自己去嘗試

func Calculate(S *Stack, Q *Queue) int {
   for i := 0; i < len(Q.elements); i++ {
      t := Q.elements[i].(string)
      switch t {
      case "+":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 + num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      case "-":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 - num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      case "*":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 * num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      case "/":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 / num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      default:
         S.push(t)
      }
   }
   i, _ := S.pop()
   return InterToNum(i)
}

源代碼

package main

import (
   "bufio"
   "errors"
   "fmt"
   "os"
   "strconv"
)

// Stack 實(shí)現(xiàn)棧
type Stack struct {
   elements []interface{}
}

func NewStack() *Stack {
   return &Stack{}
}

func (s *Stack) empty() bool {
   return len(s.elements) == 0
}

func (s *Stack) push(x interface{}) {
   s.elements = append(s.elements, x)
}

func (s *Stack) pop() (interface{}, error) {
   if s.empty() {
      return nil, errors.New("empty stack")
   }
   ret := s.elements[len(s.elements)-1]
   s.elements = s.elements[:len(s.elements)-1]
   return ret, nil
}

func (s *Stack) top() (interface{}, error) {
   if s.empty() {
      return nil, errors.New("empty stack")
   }
   return s.elements[len(s.elements)-1], nil
}

// Queue 實(shí)現(xiàn)隊(duì)列
type Queue struct {
   elements []interface{}
}

func NewQueue() *Queue {
   return &Queue{}
}

func (q *Queue) empty() bool {
   return len(q.elements) == 0
}

func (q *Queue) push(x interface{}) {
   q.elements = append(q.elements, x)
}

func (q *Queue) pop() (interface{}, error) {
   if q.empty() {
      return nil, errors.New("empty queue")
   }

   if len(q.elements) == 1 {

      ret := q.elements[0]
      r := ret.(string)
      println(r)
      q.elements = q.elements[0:0]
      return ret, nil
   } else {
      ret := q.elements[0]
      q.elements = q.elements[1 : len(q.elements)-1]
      return ret, nil
   }
}

func InterToNum(i interface{}) int {
   str := i.(string)
   ret, _ := strconv.Atoi(str)
   return ret
}

func Transform(S *Stack, Q *Queue, input string) error {
   temp := ""
   for i := 0; i < len(input); i++ {
      switch string(input[i]) {
      case "+":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }
         if S.empty() { //如果棧為空,直接入棧
            S.push(string(input[i]))
         } else { // 如果棧不為空
            m, _ := S.top()
            if m.(string) == "(" { //前一個(gè)是左括號(hào)直接入棧
               S.push(string(input[i]))
            } else { //否則全出
               for {
                  t, _ := S.pop()
                  Q.push(t.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "-":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }
         if S.empty() { //如果棧為空,直接入棧
            S.push(string(input[i]))
         } else { // 如果棧不為空
            m, _ := S.top()
            if m.(string) == "(" { //前一個(gè)是左括號(hào)直接入棧
               S.push(string(input[i]))
            } else { //否則全出
               for {
                  t, _ := S.pop()
                  Q.push(t.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "*":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }

         if S.empty() { //如果棧為空直接入棧
            S.push(string(input[i]))
         } else { //反之,將棧內(nèi)元素彈出,放入隊(duì)列
            t, _ := S.top()
            if t.(string) == "+" || t.(string) == "-" || t.(string) == "(" { //棧頂為加減號(hào)或左括號(hào),直接入棧
               S.push(string(input[i]))
            } else {
               for {
                  j, _ := S.pop()
                  Q.push(j.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" || a.(string) == "+" || a.(string) == "-" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "/":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }

         if S.empty() { //如果棧為空直接入棧
            S.push(string(input[i]))
         } else { //反之,將棧內(nèi)元素彈出,放入隊(duì)列
            t, _ := S.top()
            if t.(string) == "+" || t.(string) == "-" || t.(string) == "(" { //棧頂為加減號(hào)或左括號(hào),直接入棧
               S.push(string(input[i]))
            } else {
               for {
                  j, _ := S.pop()
                  Q.push(j.(string))
                  a, _ := S.top()
                  if S.empty() || a.(string) == "(" || a.(string) == "+" || a.(string) == "-" { //直到棧為空或者碰到左括號(hào)為止
                     break
                  }
               }
               S.push(string(input[i]))
            }
         }
      case "(":
         //別管,直接入棧
         S.push(string(input[i]))
      case ")":
         //前面有數(shù)字堆著就先讓數(shù)字入列
         if temp != "" {
            Q.push(temp)
            temp = ""
         }
         for {
            j, _ := S.pop()
            Q.push(j.(string))
            a, _ := S.top()
            if a.(string) == "(" { //直到碰到左括號(hào)為止,然后帶走左括號(hào)
               _, _ = S.pop()
               break
            }
         }
      default:
         if '0' <= input[i] && input[i] <= '9' {
            temp += string(input[i])
         } else {

            return errors.New("valid input")
         }
      }
   }
   //若還有數(shù)字沒(méi)有入隊(duì)列就入
   if temp != "" {
      Q.push(temp)
   }
   //若棧還有運(yùn)算符就出棧
   for {
      if S.empty() {
         break
      }
      t, _ := S.pop()
      Q.push(t.(string))
   }
   return nil
}

func Calculate(S *Stack, Q *Queue) int {
   for i := 0; i < len(Q.elements); i++ {
      t := Q.elements[i].(string)
      switch t {
      case "+":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 + num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      case "-":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 - num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      case "*":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 * num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      case "/":
         interNum1, _ := S.pop()
         interNum2, _ := S.pop()
         num1 := InterToNum(interNum1)
         num2 := InterToNum(interNum2)
         ret := num2 / num1
         ret1 := strconv.Itoa(ret)
         S.push(ret1)
      default:
         S.push(t)
      }
   }
   i, _ := S.pop()
   return InterToNum(i)
}

func main() {
   fmt.Println("輸入規(guī)則:")
   fmt.Println("1.可輸入加減乘除以及小括號(hào)")
   fmt.Println("2.只能輸入正整數(shù)")
   fmt.Println("3.輸入exit退出")
   for {

      fmt.Printf("請(qǐng)輸入:")
      scanner := bufio.NewScanner(os.Stdin)
      scanner.Scan() // 讀取輸入內(nèi)容,直到遇到換行符(包括空格)
      input := scanner.Text()
      if input == "exit" {
         break
      }
      S := NewStack()
      Q := NewQueue()
      err := Transform(S, Q, input)
      if err != nil {
         fmt.Println(err)
      }
      ret := Calculate(S, Q)
      fmt.Println("結(jié)果為: ", ret)
   }
}

改進(jìn)

上文只實(shí)現(xiàn)了正整數(shù)之間的加減乘除和小括號(hào)的運(yùn)算,圖方便未考慮其他可左右運(yùn)算順序的符號(hào)如:[]中括號(hào) {}大括號(hào) %取余,除此之外還可以嘗試一下實(shí)現(xiàn)輸入負(fù)數(shù)時(shí)處理的方法

以上就是基于Go語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器的詳細(xì)內(nèi)容,更多關(guān)于go計(jì)算器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go?module化?import?調(diào)用本地模塊?tidy的方法

    go?module化?import?調(diào)用本地模塊?tidy的方法

    這篇文章主要介紹了go?module化?import?調(diào)用本地模塊?tidy的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 從go語(yǔ)言中找&和*區(qū)別詳解

    從go語(yǔ)言中找&和*區(qū)別詳解

    這篇文章主要介紹了從go語(yǔ)言中找&和*區(qū)別詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Golang網(wǎng)絡(luò)模型netpoll源碼解析(具體流程)

    Golang網(wǎng)絡(luò)模型netpoll源碼解析(具體流程)

    本文介紹了Golang的網(wǎng)絡(luò)模型netpoll的實(shí)現(xiàn)原理,本文將從為什么需要使用netpoll模型,以及netpoll的具體流程實(shí)現(xiàn)兩個(gè)主要角度來(lái)展開學(xué)習(xí),感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • Go項(xiàng)目編寫Makefile規(guī)則文件概述

    Go項(xiàng)目編寫Makefile規(guī)則文件概述

    這篇文章主要為大家介紹了Go項(xiàng)目編寫Makefile文件規(guī)則概述,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • golang?db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn)

    golang?db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn)

    這篇文章主要介紹了golang db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Go語(yǔ)言開發(fā)k8s之Deployment操作解析

    Go語(yǔ)言開發(fā)k8s之Deployment操作解析

    這篇文章主要為大家介紹了Go語(yǔ)言開發(fā)k8s之Deployment操作解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐

    Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐

    這篇文章主要為大家介紹了Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • go語(yǔ)言求任意類型切片的長(zhǎng)度操作

    go語(yǔ)言求任意類型切片的長(zhǎng)度操作

    這篇文章主要介紹了go語(yǔ)言求任意類型切片的長(zhǎng)度操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Go生成base64圖片驗(yàn)證碼實(shí)例(超詳細(xì)工具類)

    Go生成base64圖片驗(yàn)證碼實(shí)例(超詳細(xì)工具類)

    這段時(shí)間需要使用圖片驗(yàn)證碼庫(kù),下面這篇文章主要給大家介紹了關(guān)于Go生成base64圖片驗(yàn)證碼的相關(guān)資料,文中給出了詳細(xì)的實(shí)例代碼,需要的朋友可以參考下
    2023-06-06
  • 深入理解 Go 語(yǔ)言中的 Context

    深入理解 Go 語(yǔ)言中的 Context

    這篇文章主要介紹了 理解 Go 語(yǔ)言中的 Context,需要的朋友可以參考下
    2020-06-06

最新評(píng)論