Perl實現逆波蘭式與遞歸計算

  近一個學期都沒有寫過博客了,甚至CSDN也很少來了,有點想念這裏了。大三忙的比高三還累,早八點出,晚十二點歸,弄得自己都不知道是在讀大學還是在工作。另一方面興趣也逐漸轉移了,對純軟件沒有以前那樣着迷,喜歡搞點基於ARM和FPGA的嵌入式系統,這一個學期都在實驗室幫老闆寫支持FPGA多個部分可重構的操作系統,得從硬件到彙編到驅動到操作系統一層一層學,累嗆了。 實驗室裏面的研究生學長談了半年的找工作的事了,見面就是offer與面試的,聽的出來似乎這幾年行情不是很好,找工作壓力挺大的。高不成低不就吧,有大牛拿到微軟的offer,也有人轉到金融了,還有轉諮詢的,年薪都超過12萬的,反正最後哪行年薪高就去哪了。

或許這就是世俗所說的一切向錢看吧,讀了二十年的書當然希望過的好些。這學期上了一門課:perl程序設計,老師是清華過來的博士後,人相當不錯,不得不說清華出來的素質還是很高的。老師除了上課,還會趁着我們價值觀成熟之前,給我們普及一些積極正面的東西。他總戲謔說自己在原來那個班級裏面算個loser了,其他同學去金融的、公務員的、國外的都混得比他好多了,當初在清華其實他也是有機會拿到一個相當不錯的公務員職位的,但是他拒絕了,選擇繼續走科研這條loser路。他說他從來沒有後悔過,因爲在這個世俗的社會裏,他並沒有浪費人生在各種應酬、附炎趨勢、虛僞與勾心鬥角當中,他說“至少現在我依然在做我喜歡做的事情”。 

其實我想我也是,進大學以來,雖然績點不算高,出國直研不太方便,獎學金沒拿過,也沒妹子,自甘寂寞;但是我也一直在做我喜歡做的事情:用軟件和硬件DIY,實現自己的想法。我沒有花大把時間與班裏的學霸不擇手段的爭奪那幾個A,沒有花大把時間在各種學生會裏腐敗、做假賬,也沒有花大把時間水人人或者哄幾個無聊的女生開心,也不是dota男;而是每天泡在圖書館與實驗室裏。不得不說是苦逼的日子了,但是欣慰的是我也依然在做我喜歡做的事情,而且哥在實驗室可能要弄到妹子了哦,呵呵。

  不抱怨了,說說perl的事情吧。其實心裏開始挺排斥Perl,因爲Perl畢竟還是腳本語言,感覺跟Javascript差不多,而且寫起來很難看。但是一個學期學下來,發現Perl相比C++在很多方面還是很優秀的,尤其是Perl對正則表達式的支持特別好,而且區別於Js,Perl能在正則表達式裏面調用函數,處理文本相當的帶勁。在實驗室處理網表文件都得靠Perl來做。

不僅如此,Perl的動態性性也特好,支持tied功能,能夠對任何變量的行爲重新定義,就感覺perl就是自己編出來的;符號引號動態創建代碼之類的都很方便;還有就是perl的package 模塊確實是我用過的最方便移植的,在CPAN裏面找到別人的模塊再直接用,別C++裏面調用別人的庫還是要方便不少。總體上說,perl不太適合團隊合作中使用,因爲不太好維護,但對於個人使用起來還是特別好用的。

  事先逆波蘭式與遞歸其實還是挺簡單的,畢竟算法不復雜。其實用perl寫出來與應C寫起來差不多了,就是perl與C兩者在內存模型方面差別太大了,perl沒有指針的都是用“引用”,實現任意維數的數據類型很方便,而且不需要事先聲明。

算法百度百科裏面如下:

一般算法

  將一個普通的中序表達式轉換爲逆波蘭表達式的一般算法是:
  (1)首先構造一個運算符棧,此運算符在棧內遵循越往棧頂優先級越高的原則。
  (2)讀入一個用中綴表示的簡單算術表達式,爲方便起見,設該簡單算術表達式的右端多加上了優先級最低的特殊符號“#”。
  (3)從左至右掃描該算術表達式,從第一個字符開始判斷,如果該字符是數字,則分析到該數字串的結束並將該數字串直接輸出。
  (4)如果不是數字,該字符則是運算符,此時需比較優先關係。
  做法如下:將該字符與運算符棧頂的運算符的優先關係相比較。如果,該字符優先關係高於此運算符棧頂的運算符,則將該運算符入棧。倘若不是的話,則將棧頂的運算符從棧中彈出,直到棧頂運算符的優先級低於當前運算符,將該字符入棧。
  (5)重複上述操作(3)-(4)直至掃描完整個簡單算術表達式,確定所有字符都得到正確處理,我們便可以將中綴式表示的簡單算術表達式轉化爲逆波蘭表示的簡單算術表達式。

代碼還是寫在下面,雖然perl代碼不太好看,但應該還是還能看懂的,直接複製下來就能跑的,希望對剛學perl的筒子們有用。

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
while(1){
	my $data=&get_input();
	if(!$data){
		print "your expr is illegal,please check it\n";next;
	}
	my @tree=&get_tree($data);
	print "The tree is: \n", Dumper(@tree)," \n";
	my $result=&count($tree[0]);
	print "The result of the expr is: $result\n";
}
 ######獲得輸入數據函數
sub get_input{
	print "Input your expr>>";
	chomp( my $inputdata=<STDIN>);
	$inputdata=~s/\s//g;   #去除所有的空白符
	if(!$inputdata){exit;}
	if($inputdata=~/[a-zA-Z\.]/)   { #做簡單檢查是否存在小數或者字符出現
		return 0;}
	$inputdata=join("",$inputdata,"#") if (substr($inputdata,length($inputdata)-1,1) ne "#"); #在最後補#
}
#get the tree of the expr
sub get_tree{
	my $data=pop;
	my ($stop,$top,$ch,@stack,@tree);
	$top=0;$stack[0]='#';
	while($top<length($data)){
		$ch=substr($data,$top,1);
		if($ch eq "+" or $ch eq "-"){
			my $op=pop(@stack);
			if($op eq '#' or $op eq '('  or  $op eq '['  or $op eq '{'){
				push(@stack,$op);push(@stack,$ch);}
			else{
				 push(@stack,$op);
				while(1){
					my $op=pop(@stack);
                    if($op eq '#' or $op eq '(' or $op eq '[' or $op eq '{'){
						push(@stack,$op);push(@stack,$ch); last;}
					else{
						my @node;
						push(@node,$op);push(@node,pop(@tree));
						push(@node,pop(@tree));push(@tree,[@node]);
					}
				}
			}
			$top=$top+1; next;
		}
		if($ch eq "*"  or $ch eq "/")
		{
			my $op=pop(@stack);
			if($op ne "*" and $op ne "/"){
				push(@stack,$op);push(@stack,$ch);}
			else{
				push(@stack,$op);
				while(1){
					my $op=pop(@stack);
					if($op ne "*" and $op ne "/"){
						push(@stack,$op);push(@stack,$ch);last;}
					else	{
						my @node;
						push(@node,$op);push(@node,pop(@tree));
						push(@node,pop(@tree));push(@tree,[@node]);
					}
				}
			}
			$top=$top+1;next;
		}
		if($ch eq '(' or $ch eq '{' or $ch eq '['){
			push(@stack,$ch);$top=$top+1;next;
		}
		if($ch eq ')' or $ch eq ']' or $ch eq '}'){
			while(1){
              my $op=pop(@stack);
			  if($op eq '('  or $op eq '['  or $op eq '{'){
				  last;}
             my @node;
			 push(@node,$op); push(@node,pop(@tree));
			 push(@node,pop(@tree)); push(@tree,[@node])
			}
			 $top=$top+1;next;
		}
		if($ch eq '#'){
			while(1){
				my $op=pop(@stack);
				if($op eq '#'){
					last;}
				else{
					my @node;
					push(@node,$op);push(@node,pop(@tree));
					push(@node,pop(@tree));push(@tree,[@node]);
				}
			}
			$top=$top+1;next;
		}
		if($ch ge '0' and $ch le '9'){
			my $num=0;
			while($ch ge '0' and $ch le '9'){
				$num=$num*10+$ch; $top=$top+1;
				$ch=substr($data,$top,1);
			}
		  push(@tree,$num);	 next;
		}
		else{
			$top=$top+1;
		}
	}
     return reverse  @tree;
}

#####檢查是否爲引用
sub judge_digit
{
	my $data=shift;
	if(ref($data) eq "ARRAY"){
		return 0;}
	else{
		return 1;}
}
#####根據樹計算最終結果
########利用遞歸函數實現
sub count
{
	my $x=shift;
	my @data=@{$x};
    if(judge_digit($data[1])==0){
		$data[1]=count($data[1]);
	}
	if(judge_digit($data[2])==0){
		$data[2]=count($data[2]);
	}
	if($data[0] eq "+"){
        return $data[1]+$data[2];
	}elsif($data[0] eq "-") {
         return $data[2]-$data[1];
	}elsif($data[0] eq "*"){
         return $data[1]*$data[2];
	}elsif($data[0] eq "/") {
         return $data[2]/$data[1];
	}
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章