算术表达式的实现,支持加减乘除,括号运算,表达式转二叉树
生活随笔
收集整理的這篇文章主要介紹了
算术表达式的实现,支持加减乘除,括号运算,表达式转二叉树
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
基本思路
首先,用戶輸入的待求表達式,也就是中綴表達式,對于人來說,這個很好理解,但是對于計算機,后綴表達式求值更加容易。如果看成一棵二叉樹,其實中綴表達式就是對一個二叉樹的中序遍歷,后綴表達式(也叫逆波蘭表達式)就是后序遍歷的結果。那么主要思路就來了:先把中綴表達式轉換成后綴表達式,再對后綴表達式進行求值。
步驟一,中綴表達式轉后綴表達式
兩個數據結構:
1,后綴表達式隊列
用于存放最后的后綴表達式
2,操作符棧
對用戶輸入的操作符進行處理
算法偽代碼:
/* 依次讀入用戶輸入的中綴表達式 如果是數字,直接入隊 如果是操作符,如果棧為空,直接入棧如果操作符為 ( 直接入棧如果操作符為 ) ,依次出棧,直到遇到第一個(,(和)都不入棧如果是其他操作符(+ - * /),則和棧頂元素進行比較優先級如果棧頂元素優先級大于等于(*和/ > +和-)操作符 ,則出棧,直到棧頂元素優先級小于操作符或棧為空 */ //偽代碼 //后綴表達式隊列 queue num; //操作符棧 stack option; while(scanf("%c",&x)){if(x 是數){num.addBack(x); //入隊}else if(option.empty() || x == '('){//如果棧為空,直接入棧,如果操作符為 ( 直接入棧option.push(x) }else if(x == ')'){//如果操作符為 ) ,依次出棧,直到遇到第一個(,(和)都不入棧while((tmp = option.pop()) != '('){num.addBack(tmp); }}else{//只是獲取棧首元素,沒有出棧while(1){tmp = option.head();if(tmp 優先級大于等于x){tmp1 = option.pop();num.addBack(tmp1); }else{break;}}option.push(x);} } //最后把所有操作符入隊 while(!option.empty()){tmp = option.pop();num.addBack(tmp); }步驟二,后綴表達式計算值
數據結構:
結果棧
用于存放計算的中間過程的值和最終結果
算法偽代碼:
/* 依次從后綴表達式隊列中取值 如果是值,直接入棧 如果是操作符,從隊列中取出兩個數,進行運算(后取出來的數作為第一個運算符),計算結果再次壓棧 */ //用于存放結果的棧 stack res; //后綴表達式隊列,上一步求出來的 queue num; while(!num.empty()){//取隊首tmp = num.getFront();if(tmp 是數){res.push(tmp);}else{num1 = num.pop();num2 = num.pop();num3 = num2 tmp num1;res.push(num3);} }步驟三,轉二叉樹
算法偽代碼:
/*主要是在計算逆波蘭表達式的時候,構造出一棵二叉樹,構造思路和計算時差不多,如果是數,就直接構造節點,如果是操作符,就把前面兩個節點提出來作為左右節點*///用于存放所有臨時節點和最后根節點的數組 treeNode all[MAX]; int n=0; //后綴表達式隊列,上一步求出來的 queue num; while(!num.empty()){//取隊首tmp = num.getFront();if(tmp 是數){res[n++] = tmp;}else{num1 = all[--n];num2 = all[--n];tmp.left = num1;tmp.right = num2;all[n++] = tmp;} }運行情況
完整代碼
/*** 計算算術表達式的值,支持 加減乘除括號 運算* 思路是,先把用戶輸入的表達式(中綴表達式,中序遍歷),格式化成逆波蘭表達式(后綴表達式,后序遍歷序列)* 再對后綴表達式進行求值*/ #include <stdio.h> #include <string.h> //通用鏈表 #include "cl_link.h"#define MAX 1024 #define IS_OPTION '0' #define IS_NUM '1'char* optionAll = "+-*/()";typedef struct bTree{char type;double num;char option;struct bTree* left;struct bTree* right; }bTree;//運算符節點 typedef struct optionNode{//用于標志運算符char type;cl_link_node node;char option; }optionNode;//操作數節點 typedef struct numNode{// 用于標志操作數char type;cl_link_node node;double num; }numNode;//運算符棧 cl_link* optionStack = NULL; //數字隊列 cl_link* numQueue = NULL; /*** 比較是否是運算符* @param optionAll 運算符表* @param aim 比較對象* @return 1 是 0 不是*/ int isOption(const char* optionAll,const char aim) {for (size_t i = 0; i < strlen(optionAll); i++) {if(aim == *(optionAll+i)){return 1;}}return 0; } /*** 比較優先級* @return 1 src >= des* 0 src < des*/ int isMaxLevel(const char src, const char des) {if(src == '*' || src == '/')return 1;if((src == '+' || src == '-') && (des == '+' || des == '-'))return 1;return 0; } void* show(void* arg) {numNode* node = cl_link_get_data(arg, numNode, node);if(node->type == IS_NUM){printf("%0.2f,", node->num);}else{optionNode* node1 = cl_link_get_data(arg, optionNode, node);printf("%c,", node1->option);}return NULL; } //計算 double cal(double num1, double num2, char option) {switch (option) {case '+':return num1+num2;case '-':return num1-num2;case '*':return num1*num2;case '/':return num1/num2;}return 0; }void pre(bTree* root){if(root != NULL){if(root->type == IS_NUM){printf("%0.2f,", root->num);}else{printf("%c,", root->option);}pre(root->left);pre(root->right);} } void mid(bTree* root){if(root != NULL){mid(root->left);if(root->type == IS_NUM){printf("%0.2f,", root->num);}else{printf("%c,", root->option);}mid(root->right);} } void back(bTree* root){if(root != NULL){back(root->left);back(root->right);if(root->type == IS_NUM){printf("%0.2f,", root->num);}else{printf("%c,", root->option);}} } int main() {//初始化運算符棧optionStack = cl_link_create();//初始化逆波蘭空隊列,即后序遍歷結果numQueue = cl_link_create();//把輸入格式化成后綴表達式 開始char expr[MAX];scanf("%s", expr);for (size_t i = 0; i < strlen(expr); i++) {//假設輸入完全合法,不是運算符就是運算數if(!isOption(optionAll, *(expr+i))){//運算數,直接入隊,numQueuenumNode* node = malloc(sizeof(numNode));node->num = atoi(expr+i);node->type = IS_NUM;int tmp = node->num;while(tmp/10 > 0){i++;tmp /= 10;}//入隊cl_link_add_back(numQueue, cl_link_get_node(node, numNode, node));}else{/*** 如果棧為空,直接入棧* 如果是( 直接入棧* 如果是) 則依次出棧到隊列中,直到遇到第一個(* 如果X是其他運算符,則依次與棧頂元素比較優先級,* 如果棧頂元素的優先級大于等于X,* 則出棧,直到棧頂元素的優先級小于X或者棧為空。* 否則 入棧*/optionNode* node = malloc(sizeof(optionNode));node->type = IS_OPTION;node->option = *(expr+i);if(optionStack->sum == 0 || *(expr+i) == '('){//如果棧為空,或者是(,直接入棧cl_link_push(optionStack, cl_link_get_node(node, optionNode, node));}else if(*(expr+i) == ')'){//如果是) 則依次出棧到隊列中,直到遇到第一個(while(1){optionNode* tmp = cl_link_get_data(cl_link_pop(optionStack), optionNode, node);if(tmp->option == '('){break;}else{cl_link_add_back(numQueue, cl_link_get_node(tmp, optionNode, node));}}}else{printf("%C,", *(expr+i));//如果X是其他運算符,則依次與棧頂元素比較優先級,如果棧頂元素的優先級大于等于X,則出棧,直到棧頂元素的優先級小于X或者棧為空。while(1){//得到棧頂元素optionNode* tmp = cl_link_get_data(cl_link_get_head(optionStack), optionNode, node);if(isMaxLevel(tmp->option, *(expr+i))){//如果優先級大于運算符,就出棧到逆波蘭隊列optionNode* tmp = cl_link_get_data(cl_link_pop(optionStack), optionNode, node);cl_link_add_back(numQueue, cl_link_get_node(tmp, optionNode, node));}else{break;}}optionNode* node = malloc(sizeof(optionNode));node->type = IS_OPTION;node->option = *(expr+i);cl_link_push(optionStack, cl_link_get_node(node, optionNode, node));}}}/*** 若運算符還有,則直接出棧*/while(optionStack->sum != 0){optionNode* tmp = cl_link_get_data(cl_link_pop(optionStack), optionNode, node);cl_link_add_back(numQueue, cl_link_get_node(tmp, optionNode, node));}//把輸入格式化成后綴表達式 結束printf("\n逆波蘭表達式(后序遍歷):");//打印逆波蘭式,就是后序遍歷結果cl_link_each(numQueue, NULL, show);bTree* allTreeNode[MAX];int n = 0;//計算逆波蘭表達式結果,用于存放臨時結果和最終結果cl_link* res = cl_link_create();while(numQueue->sum != 0){numNode* tmp = cl_link_get_data(cl_link_pop(numQueue), numNode, node);if(tmp->type == IS_NUM){//如果是數,直接入棧cl_link_push(res, cl_link_get_node(tmp, numNode, node));bTree* newNode = malloc(sizeof(bTree));newNode->left = NULL;newNode->right = NULL;newNode->type = IS_NUM;newNode->num = tmp->num;allTreeNode[n++] = newNode;}else{//如果是操作符,則pop出棧頂兩個元素,進行運算,再入棧optionNode* tmpOption = (optionNode*)tmp;numNode* num1 = cl_link_get_data(cl_link_pop(res), numNode, node);numNode* num2 = cl_link_get_data(cl_link_pop(res), numNode, node);numNode* node = malloc(sizeof(numNode));node->num = cal(num2->num, num1->num, tmpOption->option);node->type = IS_NUM;cl_link_push(res, cl_link_get_node(node, numNode, node));bTree* newNode = malloc(sizeof(bTree));newNode->left = NULL;newNode->right = NULL;newNode->type = IS_OPTION;newNode->option = tmpOption->option;newNode->right = allTreeNode[--n];newNode->left = allTreeNode[--n];allTreeNode[n++] = newNode;}}numNode* resData = cl_link_get_data(cl_link_get_head(res), numNode, node);printf("\n運算結果是%0.2f\n", resData->num);printf("前序遍歷\n");pre(allTreeNode[0]);printf("\n中序遍歷\n");mid(allTreeNode[0]);printf("\n后序遍歷\n");back(allTreeNode[0]);printf("\n\n");return 0; }涉及的隊列和棧數據結構代碼
cl_link.h
#ifndef _CL_LINK_H #define _CL_LINK_H#include <pthread.h> #include <malloc.h> #include <unistd.h> #include <stdlib.h>#define ADD_SUCCESS (0) #define ADD_FAIL (-1) #define DELETE_SUCCESS (0) #define SELETE_FAIL (-1) #define CANFIND (1) #define NOTFIND (0)typedef struct cl_link_node cl_link_node; typedef struct cl_link cl_link;/*** 鏈表節點,其他結構體需要使用鏈表數據結構,只需包含此節點* @return*/ typedef struct cl_link_node{cl_link_node* next;cl_link_node* prev; }cl_link_node;/*** 通用鏈表對象* @return*/ typedef struct cl_link{pthread_mutex_t cl_link_mutex; //鏈表鎖cl_link_node cl_link_head; //鏈表頭cl_link_node cl_link_tail; //鏈表尾int sum; //節點數 }cl_link;#define cl_link_get_node(aim, type, node) \(cl_link_node *) ((u_char *) aim + offsetof(type, node))#define cl_link_get_data(aim, type, node) \(type *) ((u_char *) aim - offsetof(type, node))/*** 創建一個鏈表對象* @return 鏈表對象地址*/ cl_link* cl_link_create();/*** 鏈表的壓棧操作* @param link 鏈表對象* @param node 新節點* @return 壓棧狀態*/ int cl_link_push(cl_link* link, void* node);/*** 鏈表的出棧操作* @param link 鏈表對象*/ void* cl_link_pop(cl_link* link); //獲取棧頂元素 void* cl_link_get_head(cl_link* link);/*** 對每個節點進行操作* @param link 鏈表對象* @param res 返回值* @param handler 處理函數*/ void cl_link_each(cl_link* link, void* res[], void* (*handler)(void* node));/*** 隊尾添加元素* @param link 隊列對象* @param node 新節點* @return 添加狀態*/ int cl_link_add_back(cl_link* link, void* node);/*** 隊頭獲取元素* @param link 隊列對象* @return 取得的元素*/ void* cl_link_get_front(cl_link* link);/*** 根據key查找節點* @param link 鏈表對象* @param key 關鍵字* @param condition 條件*/ void* cl_link_find(cl_link* link, void* key, int (*condition)(void* node, void* key));#endifcl_link.c
#include "cl_link.h"/*** 創建一個鏈表對象* @return 鏈表對象地址*/ cl_link* cl_link_create() {cl_link* link = malloc(sizeof(cl_link));if(link == NULL){write(STDERR_FILENO, "malloc error", sizeof("malloc error"));return NULL;}pthread_mutex_init(&(link->cl_link_mutex), NULL);pthread_mutex_lock(&(link->cl_link_mutex));link->cl_link_head.next = &(link->cl_link_tail);link->cl_link_head.prev = &(link->cl_link_tail);link->cl_link_tail.next = &(link->cl_link_head);link->cl_link_tail.prev = &(link->cl_link_head);link->sum = 0;pthread_mutex_unlock(&(link->cl_link_mutex));return link; }/*** 鏈表的壓棧操作* @param link 鏈表對象* @param node 新節點* @return 壓棧狀態*/ int cl_link_push(cl_link* link, void* node) {cl_link_node* new_node = (cl_link_node*)node;pthread_mutex_lock(&(link->cl_link_mutex));if(link){new_node->next = link->cl_link_head.next;link->cl_link_head.next->prev = new_node;link->cl_link_head.next = new_node;new_node->prev = &(link->cl_link_head);link->sum++;pthread_mutex_unlock(&(link->cl_link_mutex));return ADD_SUCCESS;}else{pthread_mutex_unlock(&(link->cl_link_mutex));return ADD_FAIL;} }/*** 鏈表的出棧操作* @param link 鏈表對象*/ void* cl_link_pop(cl_link* link) {pthread_mutex_lock(&(link->cl_link_mutex));if(link->sum){cl_link_node* aim = link->cl_link_head.next;link->cl_link_head.next = aim->next;aim->next->prev = &(link->cl_link_head);link->sum--;pthread_mutex_unlock(&(link->cl_link_mutex));return aim;}else{pthread_mutex_unlock(&(link->cl_link_mutex));return NULL;} }void* cl_link_get_head(cl_link* link) {return link->cl_link_head.next; }/*** 對每個節點進行操作* @param link 鏈表對象* @param res 返回值* @param handler 處理函數*/ void cl_link_each(cl_link* link, void* res[], void* (*handler)(void* node)) {pthread_mutex_lock(&(link->cl_link_mutex));int n = link->sum;void* r;cl_link_node* p = link->cl_link_head.next;cl_link_node* todo = p;while(n){todo = p;p = p->next;r = handler(todo);if(res != NULL){res[link->sum-n] = r;}n--;}pthread_mutex_unlock(&(link->cl_link_mutex)); }/*** 隊尾添加元素* @param link 隊列對象* @param node 新節點* @return 添加狀態*/ int cl_link_add_back(cl_link* link, void* node) {cl_link_node* new_node = (cl_link_node*)node;pthread_mutex_lock(&(link->cl_link_mutex));if(link){new_node->next = &(link->cl_link_tail);new_node->prev = link->cl_link_tail.prev;link->cl_link_tail.prev->next = new_node;link->cl_link_tail.prev = new_node;link->sum++;pthread_mutex_unlock(&(link->cl_link_mutex));return ADD_SUCCESS;}else{pthread_mutex_unlock(&(link->cl_link_mutex));return ADD_FAIL;} }/*** 隊頭獲取元素* @param link 隊列對象* @return 取得的元素*/ void* cl_link_get_front(cl_link* link) {return cl_link_pop(link); }/*** 根據key查找節點* @param link 鏈表對象* @param key 關鍵字* @param condition 條件*/ void* cl_link_find(cl_link* link, void* key, int (*condition)(void* node, void* key)) {pthread_mutex_lock(&(link->cl_link_mutex));int n = link->sum;cl_link_node* p = link->cl_link_head.next;while(n){if(condition(p, key) == CANFIND){pthread_mutex_unlock(&(link->cl_link_mutex));return p;}p = p->next;n--;}pthread_mutex_unlock(&(link->cl_link_mutex));return NULL; }?
轉自:https://www.jianshu.com/p/1f3622924fde
總結
以上是生活随笔為你收集整理的算术表达式的实现,支持加减乘除,括号运算,表达式转二叉树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UML各种图总结-精华
- 下一篇: 分块编码(Transfer-Encodi