java中堆棧區別,遞歸和迭代區別


來自:http://bbs.byr.cn/#!article/buptAUTA/31

1. 讀取某個文件夾下的文件

  采用深度優先的方法,遍歷文件夾,有文件就進行文件操作。

  深度優點方法:使用遞歸實現;

private void recursion (Path path) { 
   FileStatus[] children = fs.listStatus (path); 
   for(FileStatus child : children){ 
     if(child.isDir()){ 
       recursion(child.getPath()); 
     } 
     else{ 
       …… //執行文件處理代碼 
     } 
   } 
} 

  注意:當路徑深度很少的時候這樣的方法不存在問題,但是如果路徑大於100+,就會出現棧溢出的錯誤。

  Why?

  換成迭代實現

Stack<FileStatus> pathstack = new Stack<FileStatus>(); 
for(pathstack.push(fs.getFileStatus(path)); !pathstack.empty();){ 
   FileStatus cur = pathstack.pop(); 
   FileStatus[] children = fs.listStatus(cur.getPath()); 
   for(int i = 0; i < children.length; i++) { 
     final FileStatus child = children[i]; 
     if (child.isDir()) { 
       pathstack.push(child); 
     } 
     else { 
       …… //執行文件處理代碼 
     } 
   } 
} 

  問題消失了~~Why?

2. 堆和棧的區別

  堆是有序完全二叉樹,棧是一種先進后出的線性表,棧的特點是速度快,jvm的壓棧和出棧操作都是非常高效的(相對來說,堆的二叉樹遍歷是要比先進后出線性表要慢的)。

  每一個Java應用都唯一對應一個JVM實例,每一個實例唯一對應一個堆,對象的大小是不可估計的,是動態的。

  對象的應用卻放在棧中,一個對象對應了一個4btye的引用。

  

3. 遞歸和迭代的區別

  遞歸是通過一個函數進行的,函數使用了棧空間存放在函數中申明的基本數據類型(例如int,char)和堆中對象的引用(注意是引用,而非對象本身)。所以遞歸由於不斷調用自身函數體,因此會導致需要使用的棧空間不斷增加,最終導致棧溢出。

  迭代是在一個函數中的循環體,迭代使用的pathstack這個變量,在JVM棧中只有一個4字節的指針(引用的本質),而變量的主體本身使用的則是堆內存空間。

 

  堆空間相對於棧空間來說要大得多,但是如果無限制的使用堆空間,當然也會溢出,這就是java程序員都經常會遇到的OOM(OutOfMemoryError)異常。OOM異常是非常常見的堆溢出,而StackOverFlow這個棧溢出異常則非常少見,如文章所言,棧中只存放一些4字節的指針,所以雖然棧空間很小,但想撐爆棧空間也不是那么容易的事情,這就是為什么本地應用很難遇到棧溢出的原因。

  遞歸就是在過程或函數里面調用自身,而迭代是利用變量的原值推算出變量的一個新值。如果遞歸是自己調用自己的話,迭代就是A不停的調用B。顯然遞歸用了棧空間,迭代因為始終在一個函數體中,所以使用的是堆空間。迭代只會導致堆溢出(OOM)而不會導致棧溢出。 
  迭代不會使用棧空間,所以當然不會導致棧溢出。Stack類的實例變量因為使用的內存空間是處於堆空間中,因此當然可以避免棧溢出。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM