javascript的資料結構快速學-棧和佇列

thomaszhou發表於2018-01-29

準備學習《學習JavaScript資料結構與演算法》,自己也開始做一寫筆記來記錄總結,本文也是僅針對實現方面的總結。

如果出現錯誤,請在評論中指出,我也好自己糾正自己的錯誤

author: thomaszhou

棧的實現

棧,其實就是一個陣列,但是這是個非常特殊的陣列,因為棧有個特性:先進後出,什麼意思呢?看著下面的圖來講解。

原諒我是個靈魂畫手

  • 棧只有一個開口,這個開口,是進口,也是出口

    • 我們從這個口新增資料,也從這個口取出資料
  • 棧的原則:先進後出

    • 我們依次新增1,2,3進入棧中,那我們取出的第一個值是3,第二個取出的值是2,第三個是1。那如果在取出2的時候,又新增一個數呢?大家可以模擬一下
      javascript的資料結構快速學-棧和佇列
  • 定義棧類和宣告的方法

function Stack() {  //定義棧 的類
      var items = [];
      
      this.push = function(elem) {//新增元素
        return items.push(elem);
      };

      this.pop = function() {//彈出元素
        return items.pop();
      };

      this.print = function() { //輸出
        console.log(items.toString());
      };
      
      this.size = function() {//輸出棧的長度
        return items.length;
      };
      
      this.clear = function() {//將棧置為空
        return items = [];
      };
      
      this.peek = function() {//顯示頂層元素
        return items[items.length-1]
      };
      
      this.isEmpty = function() { // 判斷棧是否為空
        return items.length === 0;
      };
}
複製程式碼

棧的測試函式

(function demo1() {
  let stack1 = new Stack();  //建立棧
  stack1.push(1);
  stack1.push(2);
  stack1.push(3);
  stack1.push(4);
  stack1.print();
  console.log(stack1.pop());//4
  console.log(stack1.peek());// 3
  console.log(stack1.isEmpty());// false
  stack1.clear();
  console.log(stack1.isEmpty());// true
})();

複製程式碼
  • 棧的例子:十進位制轉換為任意進位制
    function divideBy2(elem, base) {
      var str = '',
          temp = 0,
          arr = new Stack(),//建立棧
          baseStr = '0123456789ABCDEF';
      while (elem !== 0) {
        arr.push(Math.floor(elem % base));//容易漏掉Math.floor()就會造成結果為undefine;
        elem = Math.floor(elem / base);
        // 
        //console.log(elem);  測試debug
      }
      while (!arr.isempty()) {
        console.log(arr);
        str += baseStr[arr.pop()]; // 字串也是陣列,所有要用baseStr[]。而不能用baseStr()
      }
      return str;
    }
    
    console.log(divideBy2(7, 2));
複製程式碼

佇列的實現

(1) 普通佇列

  • 佇列和棧的不同就在於:
    • 1、棧是先進後出,那就是push和pop方法
    • 2、佇列是先進先出,那就是push和shift方法
  • 我們看啊,從右邊進去,依次新增1,2,3,4,取出的第一個值是啥?是1,第二個,第三個第四個就是2,3,4.也就是說,我們新增一定是從右邊進去,取出一定是從左邊出去,也就是上面說的先進先出,先進去的,就先出來
    javascript的資料結構快速學-棧和佇列
	function Queue() {
	  let items = [];

	  this.enqueue = function(ele) {
	    items.push(ele);
		};
	  this.dequeue = function() {
	    return items.shift();
		};

	  this.front = function() {
	    return items[0];
		};
	  //	下面方法 同 棧
	  this.isEmpty = function() {
	    return items.length === 0;
		};

	  this.clear = function() {
	    items = [];
		};

	  this.size = function() {
	    return items.length;
	  };

          this.print = function() {
            console.log(items.toString());
          }
	}
複製程式碼

普通佇列的測試函式:

	(function queueDemo() {
	  var queue = new Queue();
	  queue.enqueue(1);
	  queue.enqueue(2);
	  queue.enqueue(3);
	  queue.print();    //1,2,3
	  console.log(queue.dequeue()); //1
	  console.log(queue.isEmpty()); //false
	  console.log(queue.size());    //2
	  console.log(queue.front());   //2
	  queue.clear();
	  console.log(queue.size());  // 0
	})();
複製程式碼

(2) 優先佇列

優先佇列的核心在於設定優先順序,佇列的每個資料不是單一值,而是一個值和一個優先順序id

  • 1、 採用建構函式,構造一個含有element和priority的例項
  • 2、 每次新增例項到佇列中,按照優先順序的先後插入到佇列中(splice方法)
//	優先佇列
	function PriorityQueue() {
	  let items = [];
	  function QueueElement(element, priority) {
	    this.element = element;
	    this.priority = priority;
		}

	  this.enqueue = function(element, priority) {
	    let ele = new QueueElement(element, priority);
	    if (this.isEmpty() === true) { // 佇列為空,直接push
	      items.push(ele);
	    }else {
	      // 佇列不為空,element的優先順序priority小的在前面
              for (let i = 0; i < items.length; i++) {
                if (ele.priority < items[i].priority) {
                  items.splice(i, 0, ele);
		}else {
		//  element的優先順序最低的情況-直接push到最後
                  items.push(ele);
		}
		break;
              }
	    }
	  };

      this.print = function() {
        for (let i = 0; i < items.length; i++) {
          console.log(`ele: ${items[i].element},prio: ${items[i].priority}`);
        }
      };

//		其他的方法和普通佇列相同
      this.dequeue = function() {
        return items.shift();
      };

      this.front = function() {
        return items[0];
      };
     
      this.isEmpty = function() {
        return items.length === 0;
      };

      this.clear = function() {
        items = [];
      };

      this.size = function() {
        return items.length;
      };
	}
複製程式碼

優先佇列測試函式:

(function priQueueDemo() {
  var queue = new PriorityQueue();
  queue.enqueue(1, 4);
  queue.enqueue(2, 7);
  queue.enqueue(3, 1);
  queue.print();
  
    //	ele: 3,prio: 1
	//  ele: 1,prio: 4
	//  ele: 2,prio: 7
  console.log(queue.dequeue());//QueueElement {element: 3, priority: 1}
  console.log(queue.isEmpty());//false
  console.log(queue.size());//2
  console.log(queue.front());//QueueElement {element: 1, priority: 4}
  queue.clear();
  console.log(queue.size());// 0
})();

複製程式碼

(3)迴圈佇列

迴圈佇列和普通佇列的區別:普通佇列和迴圈佇列都是後面進一個,前面進一個.不同點就在於,迴圈佇列是要將彈出的元素再返回到尾部再新增進去 核心程式碼就是queue.enqueue(queue.dequeue())

迴圈佇列的應用-擊鼓傳花 擊鼓傳花的遊戲都玩過,就是一堆人圍一個圈,然後傳遞花,輪一圈,誰拿到花就淘汰誰(我們的例子是通過設定num來表示一輪傳遞幾個人,算是一個規律性的擊鼓傳花,如果想實現真正的擊鼓傳花,那麼就設定num為random,然後設定一個範圍,就可以了,num = Math.floor(num * Math.random())

  • 所以也只是一個虛擬的遊戲
function hotPotato (nameList, num) {
  let queue = new Queue(),
    len = nameList.length;

  for (let i = 0; i < len; i++) {
    queue.enqueue(nameList[i]);
  }
  while (queue.size() > 1) {// 佇列最後剩下一個
    for (let i = 0; i < num; i++) {
      queue.enqueue(queue.dequeue());// 迴圈佇列的核心
    }
    console.log(`${queue.dequeue()}被淘汰`);
  }
  console.log(`${queue.dequeue()}勝利`);//佇列的最後一個值
}

let arr = ['thomas1', 'thomas2', 'thomas3', 'thomas4', 'thomas5'];
hotPotato(arr, 2);
//thomas3被淘汰
//thomas1被淘汰
//thomas5被淘汰
//thomas2被淘汰
//thomas4勝利


複製程式碼

相關文章