php簡單實現算術表達式轉換成逆波蘭式,並求解


最近一直在學習C/C++,可學的都是原理語法之類的,沒有實戰成績甚是使人不爽。想用C/C++寫個計算器一直是個人夙願,剛敲鍵盤,就不知能否了,想來想去仍是對計算器的算法不是很清楚。因爲本人是學php出身,因此先使用php將計算器算法給實現了一下,以便更好的學習C/C++。這個簡單的計算器採用的是逆波蘭式來作的,僅支持加減乘除四種運算,純粹我的練習記錄一下,還望多多支持。 php

  • 將算術表達式轉換成逆波蘭式
  1. 創建運算符棧stackOperator用於運算符的存儲,壓入'@';創建逆波蘭式存儲棧stackOut,並置空
  2. 預處理表達式,正、負號前加0(若是一個加號(減號)出如今最前面或左括號後面,則該加號(減號)爲正負號) 。
  3. 順序掃描表達式,若是當前字符是數字(優先級爲0的符號),則直接入棧stackOut;若是當前字符爲運算符或括號(優先級不爲0的符號),則判斷第4點 。
  4. 若當前運算符爲'(',直接入棧stackOperator
    若爲')',出棧(stackOperator)並順序輸出運算符直到遇到第一個'(',遇到的第一個'(' 出棧(stackOperator)但不輸出;
    若爲四則運算符,比較棧頂元素與當前元素的優先級:
    若是棧頂元素運算符優先級 >= 當前元素的優先級, 出棧並順序輸出運算符直到棧頂元素優先級<當前元素優先級,而後將當前元素入棧(stackOperator)
    若是棧頂元素的優先級>當前元素的優先級,直接入棧(stackOperator)
  5. 重複第3點直到表達式掃描完畢。
  6. 順序出棧(stackOperator)並將輸出的元素壓入棧stackOut,直到棧頂元素爲'@'。
  • 計算逆波蘭式
  1. 準備一個棧stack,並置空
  2. 順序讀取(從棧底到棧頂)棧stackOut,碰到操做數,入棧stack
  3. 碰到操做符,stack彈出兩個元素,運算並將運算結果入棧stack
  4. 重複執行2~3步驟,棧stack便是表達式結果。
  • 實現代碼
/**
 * php簡單實現算術表達式轉換成逆波蘭式,並求解。
 * 僅支持加減乘除四種運算
 * @author joe, joenali@163.com
 * @date 2013-01-17
 * <pre>
 *  require 'Calc.php';
 *  $calc = new Calc('(1+9)/2');
 *  echo $calc->getExpression();
 *  echo $calc->calculate();
 * </pre>
 */
class Calc {

    protected $_stackOperator = array('@');
    protected $_stackOut = array();
    protected $_operator = array('@', '(', ')', '+', '-', '*', '/');
    protected $_priority = array('@' => 0, '(' => 10, ')' => 10, '+' => 20, '-' => 20, '*' => 30, '/' => 30);

    public function __construct($expression) {
        $this->convert($expression);
    }

    /**
     * 解析字符串表達式
     * 解析字符串表達式,將數字和運算符分離,用數組存儲
     * @param string $expression
     * @return array
     */
    protected function expressionParase($expression) {
        $arr = str_split($expression);
        $data = $tmp = array();
        do {
            $item = array_shift($arr);
            if (in_array($item, $this->_operator)) {
                if ($tmp) {
                    array_push($data, implode('', $tmp));
                    $tmp = array();
                }
                array_push($data, $item);
            } else {
                array_push($tmp, $item);
            }

        } while(count($arr));
        array_push($data, implode('', $tmp));
        return $data;
    }

    /**
     * 生成逆波蘭式
     * @param string $expression
     */
    protected function convert($expression) {
        foreach ($this->expressionParase($expression) as $char) {
            if (preg_match("/^[0-9]+$/", $char)) {
                array_push($this->_stackOut, $char);
            } else if (in_array($char, $this->_operator)) {
                if ('(' == $char) {
                    array_push($this->_stackOperator, $char);
                } else if (')' == $char) {
                    while (count($this->_stackOperator) > 1) {
                        $drop = array_pop($this->_stackOperator);
                        if ('(' == $drop) {
                            break;
                        } else {
                            array_push($this->_stackOut, $drop);
                        }
                    }
                } else {
                    while (count($this->_stackOperator)) {
                        $oTop = end($this->_stackOperator);
                        if ($this->_priority[$char] > $this->_priority[$oTop]) {
                            array_push($this->_stackOperator, $char);
                            break;
                        } else {
                           $drop = array_pop($this->_stackOperator);
                            array_push($this->_stackOut, $drop);
                        }
                    }
                }
            }
        }

        while (count($this->_stackOperator)) {
            $drop = array_pop($this->_stackOperator);
            if ('@' == $drop) {
                break;
            } else {
                array_push($this->_stackOut, $drop);
            }
        }
    }

    /**
     * 獲取逆波蘭式
     * @return string
     */
    public function getExpression() {
        return implode('', $this->_stackOut);
    }

    /**
     * 計算逆波蘭式
     * @return int
     */
    public function calculate() {
        $stack = array();
        foreach ($this->_stackOut as $char) {
            if (preg_match("/^[0-9]+$/", $char)) {
                array_push($stack, $char);
            } else if (in_array($char, $this->_operator)) {
                $b = array_pop($stack);
                $a = array_pop($stack);

                array_push($stack, $this->operator($a, $b, $char));
            }
        }

        return end($stack);
    }

    protected function operator($a, $b, $o) {
        switch ($o) {
            case '+':
                return intval($a) + intval($b);
                break;
            case '+':
                return intval($a) + intval($b);
                break;
            case '-':
                return intval($a) - intval($b);
                break;
            case '*':
                return intval($a) * intval($b);
                break;
            case '/':
                return intval($a) / intval($b);
                break;
        }
    }
}
相關文章
相關標籤/搜索