2014年1月13日 星期一

javascript 雙向鍊結串列 LIST

雙向鍊結串列



<!DOCTYPE >
<html lang="zh-TW">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<title>List 雙向鍊結</title>
<meta name="description" content="" />
<meta name="author" content="hua" />
<style>
</style>
</head>
<body>
<input type="button" value="建立時間比較" id="btn1"/>
<input type="button" value="移除時間比較" id="btn2"/>
<!--
  一開始設計在Node中有 index 屬性
 但很明顯的在從最前端移除後,要對每一個節點從算index
 如此很耗效能
 於似乎思考,java的鍊結串列也有index可是效能很好怎麼做到的.
 於是想到,node根本不需要Index,index只是用來做拜訪node的條件.
 因此在重新修改一次
-->

<script type="text/javascript">
(function(window){

     function getList(){
            function List(){              
               var firstNode=null;
               var lastNode=null;
               var count=0;
             
               var getNode = function(leftNode, rightNode, val){    
                   return{
                       'left':leftNode,
                       'right':rightNode,
                       'value':val,
                       'destory':function(){
                           this.left = null;
                           this.right = null;
                           this.value = null;
                       }                
                   };            
               }
           

               /**list目前長度*/
               this.length = function(){
                   return count;
               };            
             
               /**索引值的格式檢查*/
               var checkIndex = function(index){
                  //判斷index是否有值                              
                   if(!index && index!= 0){
                       throw new Error('index is empty!');
                   }
                   //判斷是否為數字
                   if(isNaN(index)){
                       throw new Error('index type error!');
                   }
                             
                   // /^\d+$/ //非負整數(正整數 + 0)
                   // /^[0-9]*[1-9][0-9]*$/ //正整數
                   // ^((-\d+)|(0+))$/ //非正整數(負整數 + 0)
                   // /^-[0-9]*[1-9][0-9]*$/ //負整數
                   // /^-?\d+$/ //整數
                 
                   //是否為整數
                   if(!index.toString().match(/^-?\d+$/)){
                       throw new Error('index not integer!');
                   }          
                 
                   //索引範圍檢察
                   if( index > count-1 || index < 0){
                       throw new Error('Index Out');  //索引超出範圍
                   }              
               };                
           
              /**
               * private
               * 由後端往前找到對應的節點
               */
              var lastNodeOf = function(index){
                  try{
                     checkIndex(index);
                  }catch(error){
                     //error.message;
                     throw error;
                  }              
                  var node = lastNode;                
                  while(count-1 > index){
                      node = node.left;
                      index++;
                  }            
                  return node;
              };
           
              /**
               * private
               * 由前端往後找到對應的節點
               */
              var firstNodeOf = function(index){
                   try{
                     checkIndex(index);
                  }catch(error){
                     //error.message;
                     throw error;
                  }
                  var node = firstNode;
                  while(index > 0){
                      node = node.right;
                      index--;
                  }              
                  return  node;
              };
           
              /**
               * private
               * 由index找到一個節點,會自動判斷從後開始找起或重後開始找起
               */
               var getNodeByIndex = function(index){
                  try{  
                       //計算參考值,當索引大於此中心點,則由尾部往前找,若小於此中心點則由頭部開始找,至少讓搜尋時間/2                
                       var centIndex = Math.floor(count/2);
                       return (index > centIndex) ? lastNodeOf(index) : firstNodeOf(index);                
                  }catch(error){              
                     //error.message;
                     throw error;
                  }
               }
       
              /**
               * public
               * 由後端節點往前找回List內容物
               */
              this.lastItemOf = function(index){
                  return  lastNodeOf(index).value;
              };
           
              /**
               * public
               * 由前端節點往後找回List內容物
               */
              this.firstItemOf = function(index){
                  return  firstNodeOf(index).value;
              }
             
               /**
                * 由index找回一個item
                * 會自己由index判斷由後端開始找或前端開始找
                */
               this.getItem = function(index){
                  return getNodeByIndex(index).value;
               };
             
               /**由傳入的value取得index*/
               this.getIndex = function(value){
                  var node = firstNode;
                  var index = 0;
                  while(node != null && node.value !== value){
                      node = node.right;
                      index++;
                  }
                  return (node != null) ? index : -1 ;
               };
           
           
           
               /**
                * 加入一個項目,加入成功返回true,失敗返回false
                */
               this.add = function(value){                                
                   try{
                       if(firstNode==null){
                           firstNode = getNode(null, null, value);                        
                           lastNode = firstNode;
                           count++;
                           return true;
                       }else{
                           lastNode.right = getNode(lastNode, null, value);  //目前結點的右連結,連結一個新結點
                           lastNode = lastNode.right;
                           count++;
                           return true;                        
                       }
                   }catch(error){
                       return false;
                   }                
               };
             
               this.addAt = function(value,index){                
                   var originalNode = getNodeByIndex(index); //取回原位置的node                  
                   var node;
                 
                   if(originalNode.left == null){
                       //代表原位置的node前面沒有結點,表示要插在index 為0的位置
                       //left,right,index,value
                       node = getNode(null, originalNode, value);
                       count++;
                       firstNode = node;
                       originalNode.left = node;                                    
                   }else{
                       node = getNode(originalNode.left, originalNode, value);
                       count++;                    
                       originalNode.left.right = node;
                       originalNode.left = node;                    
                     
                       if(originalNode.right == null){
                           //如果是最後端,需要在處理以下動作
                           lastNode = originalNode;
                           originalNode.right = null;
                       }
                   }                
                   return value;                      
               };
             
               /**
                * private
                * 只剩下最後一個結的的移除動作
                */
               var nolyOneClear = function(){
                   var val = lastNode.value;
                   lastNode.destory();
                   firstNode = null;
                   lastNode = null;
                   count--;
                   return val;
               };
             
               /**
                * 移除最後一個項目,並回傳內容值。
                */
               this.removeLastItem = function(){
                   var val;        
                   if(firstNode === lastNode){
                       val = nolyOneClear();                    
                    }else{
                       var nod = lastNode.left;
                       nod.right = null;
                       val = lastNode.value;
                       lastNode.destory();
                       lastNode = nod;
                       count--;
                       nod = null;
                    }
                    return val;
               };
             
               /**
                * 移除第一個節點,由於要重新計算index,所以效能會比由後方端點移除還差
                */
               this.removeFirstItem = function(){
                   var val;
                   if(firstNode === lastNode){
                      val = nolyOneClear();
                   }else{
                       var node = firstNode.right;
                       node.left = null;
                       val =  firstNode.value;
                       firstNode.destory();
                       firstNode = node;
                       count--;
                       node = null;
                   }
                   return val;
               };
             

               this.removeAt = function(index){
                   var originalNode = getNodeByIndex(index); //取回原位置的node                                                      
               
                   if(originalNode.left == null){
                       return this.removeFirstItem();
                   }          
                         
                   if(originalNode.right == null){
                       return this.removeLastItem();
                   }
                 
                   var val = originalNode.value;
                   var node = originalNode.left;
                   originalNode.left.right = originalNode.right;                
                   originalNode.right.left = originalNode.left;
                   originalNode.destory();
                   count--;
                   return val;
               };
             
              this.remove = function(value){
                  var node = firstNode;
                   var index = 0;          
                  if(node.right == null && node.value === value){                    
                     return nolyOneClear();
                  }
               
               
                  while(node.right != null){
                      index++;
                       node = node.right;
                      if(node.value == value){
                          return this.removeAt(index);
                      }
                   
                 
                  }
               
                  return -1;
               };
                           
             
             
               /**
                * 清出所有內容
                */
               this.clear = function(){
                   var node = lastNode;
                   while(firstNode!= null ){
                       this.removeLastItem();
                   }
               }
                           
           

           
              /**
               *排序
               */
              this.sort = function(){
               
              };
           
              /**
               * 排序,依傳入的比較規則函是實做
               */
              this.sortByCompare = function(CompareFun){
               
               
              }
              /**
               * 反轉串列
               */
              this.reverse = function(){
               
              };
           
              /**複製*/
              this.clone = function(){
               
              };
          }
          return new List();
     }
   
   
    //-----------------------------
    // 以下開始試測試程式碼
    //-----------------------------
 
 
   
     function createList(e) {
         
           var myList =  getList();
           var time = new Date().getTime();
           for(var i = 0 ; i < 100000 ; i++){
               myList.add(i);
           }
           time = new Date().getTime() - time;
         
           var myArray=[];
           var time2 = new Date().getTime();
           for(var j = 0 ; j < 100000 ; j++){
               myArray[j] = j;
           }
           time2 = new Date().getTime() - time2;
         
           document.write('<p>'+ 'List length -> '  + myList.length()  +   '</p>');
            document.write('<p>'+ 'List index 6 -> '  + myList.getItem(6)  +   '</p>');
           document.write('<p>'+ 'Create '+ i + 'List time -> '  + time  +   'ms</p>');
         
           document.write('<p>'+ 'array length -> '  + myArray.length  +   '</p>');
             document.write('<p>'+ 'array index 6 -> '  + myArray[6]  +   '</p>');
           document.write('<p>'+ 'Create '+ j + 'array time -> '  + time2  +   'ms</p>');        
         
    };
 
   function removeFirstItem(e){
           var myList =  getList();      
           for(var i = 0 ; i < 100000 ; i++){
               myList.add(i);
           }        
           var myArray=[];        
           for(var j = 0 ; j < 100000 ; j++){
               myArray[j] = j;
           }
          document.write('<p>'+ 'List length -> '  + myList.length()  +   '</p><br/>');
          document.write('<p>'+ 'array length -> '  + myArray.length  +   '</p><br/>');
         
   
           var time = new Date().getTime();
           for(var i = 0 ; i < 100000 ; i++){
               myList.removeFirstItem();
           }
           time = new Date().getTime() - time;
         
         
           var time2 = new Date().getTime();
           for(var j = 0 ; j < 100000 ; j++){
               myArray.shift();
           }
           time2 = new Date().getTime() - time2;
         
     
           document.write('<p>'+ 'remove list '+ i + 'List time -> '  + time  +   'ms</p><br/>');        
           document.write('<p>'+ 'remove array '+ j + 'List time -> '  + time2  +   'ms</p><br/>');
           document.write('<p>'+ 'List length -> '  + myList.length()  +   '</p><br/>');
           document.write('<p>'+ 'array length -> '  + myArray.length  +   '</p><br/>');
         
         
   }
 
    document.getElementById('btn1').addEventListener('click' , createList , false);
    document.getElementById('btn2').addEventListener('click' , removeFirstItem , false);
 
 




 
   var list = getList();
   list.add(1);
   list.add(2);
   list.add(3);
   list.add(4);
   list.add(5);
   list.add(6);
   list.add(7);
   list.add(8);
   list.add(9);
   list.add(10);
   list.add(11);
   list.add(12);
   console.log("[1,2,3,4,5,6,7,8,9,10,11,12]");
   console.log("length " + list.length());
   console.log("index 0  is  " + list.getItem(0));
   console.log("index 1  is  " + list.getItem(1));
   console.log("index 2  is  " + list.getItem(2));
   console.log("index 3  is  " + list.getItem(3));
   console.log("index 4  is  " + list.getItem(4));
   console.log("index 5  is  " + list.getItem(5));
   console.log("index 6  is  " + list.getItem(6));
   console.log("index 7  is  " + list.getItem(7));
   console.log("index 8  is  " + list.getItem(8));
   console.log("index 9  is  " + list.getItem(9));
   console.log("index 10  is  " + list.getItem(10));
   console.log("index 11 is  " + list.getItem(11));
   console.log("--------------------------");
   console.log("removeFirstItem * 2");
   list.removeFirstItem();
   list.removeFirstItem();
   console.log("index 0  is  " + list.getItem(0));
 
   console.log("--------------------------");
   console.log("length 0  is  " + list.length());
   console.log("index length -1   is  " + list.getItem(list.length()-1));

   console.log("--------------------------");
   console.log("removeLastItem *2 ");
   list.removeLastItem();
   list.removeLastItem();
   console.log("length 0  is  " + list.length());
   console.log("index length -1   is  " + list.getItem(list.length()-1));
 
   console.log("--------------------------");
   console.log("clear");
   list.clear();
   console.log("length 0  is  " + list.length());
 
   console.log("^^^^^^^^^^^^^^^^^^^^^");
    console.log("roun 2");
   list.add(1);
   list.add(2);
   list.add(3);
   list.add(4);
   list.add(5);
   list.add(6);
   list.add(7);
   list.add(8);
   list.add(9);
   list.add(10);
   list.add(11);
 
   console.log("length 0  is  " + list.length());
 
   console.log("index 7  is  " + list.getItem(7));
   list.removeAt(7);
 
   console.log("index 7  is  " + list.getItem(7));
   list.addAt("CC",7);
    console.log("index 6  is  " + list.getItem(6));
    console.log("index 7  is  " + list.getItem(7));
    console.log("index 8  is  " + list.getItem(8));
 
 
      console.log("^^^^^^^^^^^^^^^^^^^^^");
    console.log("roun 3");
    list.clear();
     list.add(1);
   list.add(2);
   list.add(3);
   list.add(4);
   list.add(5);
   list.add(6);
   list.add(7);
   list.add(8);
   list.add(9);
   list.add(10);
   list.add(11);
    console.log("length 0  is  " + list.length());
    console.log("index 4  is  " + list.getItem(4));
    list.remove(5);
     console.log("length 0  is  " + list.length());
     console.log("index 4  is  " + list.getItem(4));
      console.log("index 9  is  " + list.getItem(9));
      console.log("index 2 is  " + list.getItem(2));
      console.log("length 0  is  " + list.length());
      list.remove(2);
       console.log("index 2 is  " + list.getItem(2));
       console.log("length 0  is  " + list.length());
 
})(window);
</script>
</body>

沒有留言:

張貼留言