javascript
逆波兰计算器android源码简书,计算器的核心算法-JavaScript实现(逆波兰表达式)...
最終計算器的掩飾效果,歡迎大家來找BUG.
http://codepen.io/lvanboy/full/LxKVxJ/
功能:
1.按照運算符的優先級運算
2.利用上次的結果繼續運算
3.多個數字混合運算
1、將一個中序表達式轉化成為逆波蘭表達式
首先維護的是兩個棧,我們這里暫且稱為S1和S2,S1中的結果最后存的就是逆波蘭表達式,S2中將用于暫時存放運算符并且在最終形成逆波蘭表達式的時候,該棧是會清空的。下面我們看看怎樣具體的形成逆波蘭表達式。
在此首先定義一下運算符的優先級關系,從小到達排序,相同優先級沒有用逗號隔開:(,+-,*\,負號,)。
從左至右遍歷一個給定的中序表達式,也就是我們常規的數學計算的表達式。
(1)** 如果遇到的是數字,我們直接加入到棧S1中;**
(2)** 如果遇到的是左括號,則直接將該左括號加入到棧S2中;**
(3)** 如果遇到的是右括號,那么將棧S2中的運算符一次出棧加入到棧S1中,直到遇到左括號,但是該左括號出棧S2并不加入到棧S1中;**
(4)** 如果遇到的是運算符,包括單目運算符和雙目運算符,我們按照下面的規則進行操作:**
如果此時棧S2為空,則直接將運算符加入到棧S2中;
如果此時棧S2不為空,當前遍歷的運算符的優先級大于等于棧頂運算符的優先級,那么直接入棧S2;
如果此時棧S2不為空,當前遍歷的運算符的優先級小于棧頂運算符的優先級,則將棧頂運算符一直出棧加入到棧S1中,直到棧為空或者遇到一個運算符的優先級小于等于當前遍歷的運算符的優先級,此時將該運算符加入到棧S2中;
(5)** 直到遍歷完整個中序表達式之后,棧S2中仍然存在運算符,那么將這些運算符依次出棧加入到棧S1中,直到棧為空。**
按照上面的五條操作反復進行完成,那么棧S1中存放的就是逆波蘭表達式。
2、利用逆波蘭表達式求值
利用逆波蘭表達式求計算式的值其實很簡單,正式因為這一點,所以逆波蘭表達式才在編譯原理中被用于計算一個表達式的值。
下面來具體看看如何求一個逆波蘭表達式的值:
我們此時維護一個數據結果棧S3,我們將會看到該棧中最后存放的是最終的表達式的值。我們從左至右的遍歷棧S1,然后按照下面的規則進行操作棧S3.
(1)** 如果遇到的是數字,那么直接將數字壓入到S3中;**
(2) ** 如果遇到的是單目運算符,那么取S3棧頂的一個元素進行單目運算之后,將結果再次壓入到棧S3中;**
(3)** 如果遇到的是雙目運算符,那么取S3棧頂的兩個元素進行,首先出棧的在左,后出棧的在右進行雙目運算符的計算,將結果再次壓入到S3中。**
按照上面的三個規則,遍歷完整個棧S1,那么最后S3中的值就是逆波蘭表達式的值了,所以我們可以看出來使用逆波蘭表達式進行求值是很簡單的,只有兩種操作要么是直接壓棧,要么是運算之后將結果壓棧。
3、JavaScript 具體實現代碼,為了方便dom操作引用了jQuery
HTML 結構是這樣的:樣式大家自己發揮
calculatorCalculator
下面是參考代碼:這里獨立實現了AC,Ans,CE(在原先的算法實現)
$(function(){
var nums = ["AC","CE","%","/",
"7","8","9","*","4","5","6","-",
"1","2","3","+",".","0","Ans","="];
//利用數組模擬堆棧,新建兩個堆棧
//s1 的結果 存放的是 逆波蘭表達式,
//s2 暫時存放運算符
var s1 = [] ,s2 = [];
// 定義運算符 優先級 ,
var signPriority = [["+","-"],["*","/","%"],["-","."]];
// 定義數字正則
var reg = /\d+/;
// 單目規則
var regSingle = /[\-\.]/;
// 不可顯示字符
var hidden = /[AC=CE=Ans]/;
// 連接顯示數字
var concatNum="";
// 保存結果
var s3 = [],result;
//連接計算數字
var sum ="";
//計CE的次數
var count = 0;
//迭代元素
var key = $("#nums").children();
key.each(function(index,val){
//寫入計算器按鈕的值
$(val).text(nums[index]);
//實現的按鈕動態效果
$(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);
}
//如果是數字,拼接數字
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清除一個值,不顯示該值
if($(this).text()=="CE"){
concatNum = concatNum.substr(0,concatNum.length-1);
// s1.pop();
count++;
s1[s1.length-count]=parseInt(concatNum);
$("#output").text(concatNum);
}
//如果s2 為空,直接將運算符壓入s2中
if(s2.length==0){
s2.push($(this).text());
}else{
//如果s2不為空,判斷運算符優先級
var sTopElem = s2[s2.length-1];
var curElem = $(this).text();
//如果當前優先級大于棧頂優先級,直接入s2
if(judgePriority(curElem,sTopElem)){
s2.push(curElem);
}else{
//堆棧不為空,當前元素不小于棧頂元素優先級,一直從s2出棧到s1
while(!judgePriority(curElem,sTopElem)&&s2.length!==0){
s1.push(s2.pop());
}
//不滿足上面條件,再把當前符號入棧s2
s2.push($(this).text());
}
}
}
//計算逆波蘭堆棧
if($(this).text()=="="){
var tem = [];
//清空鏈接字符
concatNum="";
//清空符號
s2 = [];
//清空計數器
count = 0;
//遍歷s1
for(var i=0;i
//如果當前為數字,直接入棧s3
if(reg.test(s1[i])){
s3.push(parseFloat(s1[i]));
}
//單目運算
else if(regSingle.test(s1[i])){
if(s1[i]=="-"){
s3.push(-s3.pop());
}
if(s1[i]=="."){
s3[s3.length-2]=(s3.pop()/10);
}
}else{ //雙目運算
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=[];
//最終結果s3
if(s3.length==1){
//判斷結果是否非法
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);
}
}
}
})
//判斷當前運算符與棧頂運算符優先級
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;
}
};
})
})
總結
以上是生活随笔為你收集整理的逆波兰计算器android源码简书,计算器的核心算法-JavaScript实现(逆波兰表达式)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android m权限工具类,andro
- 下一篇: vba 将html转换excel,利用V