日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

逆波兰计算器android源码简书,计算器的核心算法-JavaScript实现(逆波兰表达式)...

發(fā)布時(shí)間:2023/12/18 javascript 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 逆波兰计算器android源码简书,计算器的核心算法-JavaScript实现(逆波兰表达式)... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最終計(jì)算器的掩飾效果,歡迎大家來找BUG.

http://codepen.io/lvanboy/full/LxKVxJ/

功能:

1.按照運(yùn)算符的優(yōu)先級(jí)運(yùn)算

2.利用上次的結(jié)果繼續(xù)運(yùn)算

3.多個(gè)數(shù)字混合運(yùn)算

1、將一個(gè)中序表達(dá)式轉(zhuǎn)化成為逆波蘭表達(dá)式

首先維護(hù)的是兩個(gè)棧,我們這里暫且稱為S1和S2,S1中的結(jié)果最后存的就是逆波蘭表達(dá)式,S2中將用于暫時(shí)存放運(yùn)算符并且在最終形成逆波蘭表達(dá)式的時(shí)候,該棧是會(huì)清空的。下面我們看看怎樣具體的形成逆波蘭表達(dá)式。

在此首先定義一下運(yùn)算符的優(yōu)先級(jí)關(guān)系,從小到達(dá)排序,相同優(yōu)先級(jí)沒有用逗號(hào)隔開:(,+-,*\,負(fù)號(hào),)。

從左至右遍歷一個(gè)給定的中序表達(dá)式,也就是我們常規(guī)的數(shù)學(xué)計(jì)算的表達(dá)式。

(1)** 如果遇到的是數(shù)字,我們直接加入到棧S1中;**

(2)** 如果遇到的是左括號(hào),則直接將該左括號(hào)加入到棧S2中;**

(3)** 如果遇到的是右括號(hào),那么將棧S2中的運(yùn)算符一次出棧加入到棧S1中,直到遇到左括號(hào),但是該左括號(hào)出棧S2并不加入到棧S1中;**

(4)** 如果遇到的是運(yùn)算符,包括單目運(yùn)算符和雙目運(yùn)算符,我們按照下面的規(guī)則進(jìn)行操作:**

如果此時(shí)棧S2為空,則直接將運(yùn)算符加入到棧S2中;

如果此時(shí)棧S2不為空,當(dāng)前遍歷的運(yùn)算符的優(yōu)先級(jí)大于等于棧頂運(yùn)算符的優(yōu)先級(jí),那么直接入棧S2;

如果此時(shí)棧S2不為空,當(dāng)前遍歷的運(yùn)算符的優(yōu)先級(jí)小于棧頂運(yùn)算符的優(yōu)先級(jí),則將棧頂運(yùn)算符一直出棧加入到棧S1中,直到棧為空或者遇到一個(gè)運(yùn)算符的優(yōu)先級(jí)小于等于當(dāng)前遍歷的運(yùn)算符的優(yōu)先級(jí),此時(shí)將該運(yùn)算符加入到棧S2中;

(5)** 直到遍歷完整個(gè)中序表達(dá)式之后,棧S2中仍然存在運(yùn)算符,那么將這些運(yùn)算符依次出棧加入到棧S1中,直到棧為空。**

按照上面的五條操作反復(fù)進(jìn)行完成,那么棧S1中存放的就是逆波蘭表達(dá)式。

2、利用逆波蘭表達(dá)式求值

利用逆波蘭表達(dá)式求計(jì)算式的值其實(shí)很簡單,正式因?yàn)檫@一點(diǎn),所以逆波蘭表達(dá)式才在編譯原理中被用于計(jì)算一個(gè)表達(dá)式的值。

下面來具體看看如何求一個(gè)逆波蘭表達(dá)式的值:

我們此時(shí)維護(hù)一個(gè)數(shù)據(jù)結(jié)果棧S3,我們將會(huì)看到該棧中最后存放的是最終的表達(dá)式的值。我們從左至右的遍歷棧S1,然后按照下面的規(guī)則進(jìn)行操作棧S3.

(1)** 如果遇到的是數(shù)字,那么直接將數(shù)字壓入到S3中;**

(2) ** 如果遇到的是單目運(yùn)算符,那么取S3棧頂?shù)囊粋€(gè)元素進(jìn)行單目運(yùn)算之后,將結(jié)果再次壓入到棧S3中;**

(3)** 如果遇到的是雙目運(yùn)算符,那么取S3棧頂?shù)膬蓚€(gè)元素進(jìn)行,首先出棧的在左,后出棧的在右進(jìn)行雙目運(yùn)算符的計(jì)算,將結(jié)果再次壓入到S3中。**

按照上面的三個(gè)規(guī)則,遍歷完整個(gè)棧S1,那么最后S3中的值就是逆波蘭表達(dá)式的值了,所以我們可以看出來使用逆波蘭表達(dá)式進(jìn)行求值是很簡單的,只有兩種操作要么是直接壓棧,要么是運(yùn)算之后將結(jié)果壓棧。

3、JavaScript 具體實(shí)現(xiàn)代碼,為了方便dom操作引用了jQuery

HTML 結(jié)構(gòu)是這樣的:樣式大家自己發(fā)揮

calculator

Calculator

下面是參考代碼:這里獨(dú)立實(shí)現(xiàn)了AC,Ans,CE(在原先的算法實(shí)現(xiàn))

$(function(){

var nums = ["AC","CE","%","/",

"7","8","9","*","4","5","6","-",

"1","2","3","+",".","0","Ans","="];

//利用數(shù)組模擬堆棧,新建兩個(gè)堆棧

//s1 的結(jié)果 存放的是 逆波蘭表達(dá)式,

//s2 暫時(shí)存放運(yùn)算符

var s1 = [] ,s2 = [];

// 定義運(yùn)算符 優(yōu)先級(jí) ,

var signPriority = [["+","-"],["*","/","%"],["-","."]];

// 定義數(shù)字正則

var reg = /\d+/;

// 單目規(guī)則

var regSingle = /[\-\.]/;

// 不可顯示字符

var hidden = /[AC=CE=Ans]/;

// 連接顯示數(shù)字

var concatNum="";

// 保存結(jié)果

var s3 = [],result;

//連接計(jì)算數(shù)字

var sum ="";

//計(jì)CE的次數(shù)

var count = 0;

//迭代元素

var key = $("#nums").children();

key.each(function(index,val){

//寫入計(jì)算器按鈕的值

$(val).text(nums[index]);

//實(shí)現(xiàn)的按鈕動(dòng)態(tài)效果

$(val).on("mousedown",function(e){

$(this).css({"box-shadow":"-1px -1px 3px #666"})

})

$(val).on("mouseup",function(e){

$(this).css({"box-shadow":"2px 2px 3px #555"})

})

$(val).on("click",function(e){

//顯示字符

if(!hidden.test($(this).text())){

concatNum += $(this).text();

$("#output").text(concatNum);

}

//如果是數(shù)字,拼接數(shù)字

if(reg.test($(this).text())){

sum += $(this).text();

}else{

s1.push(parseInt(sum));

sum =" ";

//Ans 保存上一次的值,不顯示該值

if($(this).text()=="Ans"){

s1.push(s3[0]);

s3 = [];

}else{

s3 = [];

}

//AC功能清空屏幕,不顯示該鍵值

if($(this).text()=="AC"){

$("#output").text("");

concatNum="";

s1 = [];

s2 = [];

s3 = [];

}

//CE清除一個(gè)值,不顯示該值

if($(this).text()=="CE"){

concatNum = concatNum.substr(0,concatNum.length-1);

// s1.pop();

count++;

s1[s1.length-count]=parseInt(concatNum);

$("#output").text(concatNum);

}

//如果s2 為空,直接將運(yùn)算符壓入s2中

if(s2.length==0){

s2.push($(this).text());

}else{

//如果s2不為空,判斷運(yùn)算符優(yōu)先級(jí)

var sTopElem = s2[s2.length-1];

var curElem = $(this).text();

//如果當(dāng)前優(yōu)先級(jí)大于棧頂優(yōu)先級(jí),直接入s2

if(judgePriority(curElem,sTopElem)){

s2.push(curElem);

}else{

//堆棧不為空,當(dāng)前元素不小于棧頂元素優(yōu)先級(jí),一直從s2出棧到s1

while(!judgePriority(curElem,sTopElem)&&s2.length!==0){

s1.push(s2.pop());

}

//不滿足上面條件,再把當(dāng)前符號(hào)入棧s2

s2.push($(this).text());

}

}

}

//計(jì)算逆波蘭堆棧

if($(this).text()=="="){

var tem = [];

//清空鏈接字符

concatNum="";

//清空符號(hào)

s2 = [];

//清空計(jì)數(shù)器

count = 0;

//遍歷s1

for(var i=0;i

//如果當(dāng)前為數(shù)字,直接入棧s3

if(reg.test(s1[i])){

s3.push(parseFloat(s1[i]));

}

//單目運(yùn)算

else if(regSingle.test(s1[i])){

if(s1[i]=="-"){

s3.push(-s3.pop());

}

if(s1[i]=="."){

s3[s3.length-2]=(s3.pop()/10);

}

}else{ //雙目運(yùn)算

if(s1[i]=="+"){

s3.push(parseFloat(s3.pop())+parseFloat(s3.pop()));

}

if(s1[i]=="-"){

s3.push(parseFloat(s3.pop())-parseFloat(s3.pop()));

}

if(s1[i]=="*"){

s3.push(parseFloat(s3.pop())*parseFloat(s3.pop()));

}

if(s1[i]=="/"){

s3.push(parseFloat(s3.pop())/parseFloat(s3.pop()));

}

if(s1[i]=="%"){

s3.push(parseFloat(s3.pop())%parseFloat(s3.pop()));

}

}

}

//清空逆波蘭

s1=[];

//最終結(jié)果s3

if(s3.length==1){

//判斷結(jié)果是否非法

if(isNaN(s3[0])){

$("#output").text("非法操作");

s3 = [];

}else{

$("#output").text(s3[0]);

}

}else{

result=s3[0]+s3[1];

if(isNaN(result)){

$("#output").text("非法操作");

s3 = [];

}else{

$("#output").text(result);

}

}

}

})

//判斷當(dāng)前運(yùn)算符與棧頂運(yùn)算符優(yōu)先級(jí)

function judgePriority(sign1,sign2){

var index1,index2;

for(var i=signPriority.length-1;i>=0;i--){

for(var j=signPriority[i].length-1;j>=0;j--){

if(sign1==signPriority[i][j]){

index1=i;

}

if(sign2==signPriority[i][j]){

index2=i;

}

}

}

if(index1>index2){

return true;

}else{

return false;

}

};

})

})

總結(jié)

以上是生活随笔為你收集整理的逆波兰计算器android源码简书,计算器的核心算法-JavaScript实现(逆波兰表达式)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。