上篇數據結構那些事(一)已經介紹了數組,列表和棧。這篇咱們將介紹隊列,鏈表,字典。數組
隊列的兩種主要操做是:向隊列中插入新元素和刪除隊列中的元素。入隊操做在隊尾插入新元素,出隊在隊頭刪除元素。 接下來,咱們來設計一個隊列Queue類:bash
function Queue(){
this.dataStore = [];//存儲
this.enqueue = enqueue;//入隊
this.dequeue = dequeue;//出隊
this.front = front;//隊首
this.back = back;//隊尾
this.toString = toString;//顯示隊列元素
this.empty = empty;//清除
}
複製代碼
實現上面的操做方法:cookie
function enqueue(e){
this.dataStore.push(e);
}
function dequeue(e){
this.dataStore.shift(e)
}
function front(){
return this.dataStore[0]
}
function back(){
return this.dataStore[this.dataStore.length - 1]
}
function toString(){
let retStr = "";
for (let i = 0; i<this.dataStore.length; ++i){
retStr += this.dataStore[i] + "\n";
}
return retStr;
}
function empty(){
if(this.dataStore.length === 0){
return true;
}else{
return false;
}
}
複製代碼
上面咱們實現了一個基礎的隊列。但現實生活中,可能會出現相似軍人優先,重病患優先這樣的場景,那樣咱們上面的隊列就沒法知足了。這時,咱們須要一個優先隊列。 從優先隊列中刪除元素時,須要考慮優先權的限制。咱們來定義一下存儲在隊列中的元素:數據結構
function Person(name, code){
this.name = name;
this.code = code; //表示優先級,越小優先級越高
}
複製代碼
如今,須要從新定義dequeue()方法。post
function dequeue(){
let p = this.dataStore[0].code;
for(let i =1 ; i < this.dataStore.length; ++i){
if(this.dataStore[i].code < p){
p = i
}
}
return this.dataStore.splice(p, 1);
}
複製代碼
鏈表元素依靠相互之間的關係進行引用。遍歷鏈表,就是跟着鏈表,從鏈表的首元素一直走到尾元素,鏈表的尾元素通常指向null。ui
下圖演示了在eggs後插入cookies操做this
下圖演示了刪除操做 從上面的幾張圖,咱們能直觀的感覺到,鏈表作這些插入和刪除操做比數組要便捷的多。由於數組執行插入刪除操做時還須要對應的改變數組中其餘元素的索引。而鏈表只須要改變對應節點的指向便可完成操做,二者不可同日而語。咱們設計的鏈表包含兩個類。Node類用來表示節點,LinkedList類提供插入,刪除,顯示元素等方法。spa
function Node(e){
this.element = e;
this.next = null;
}
function LList(){
this.head = new Node("head");
this.find = find; //遍歷鏈表,查找給定數據
this.findPrev = findPrev; //遍歷鏈表,查找給定數據前面一個節點
this.insert = insert; //插入一個節點
this.remove = remove; //刪除
this.display = display; //顯示
}
複製代碼
實現上面的方法:設計
function find(e){
let currNode = this.head;
while(currNode.element !== e){
currNode = currNode.next;
}
return currNode;
}
function insert(newEl, e){
let newNode = new Node(newEl);
let current = this.find(e);
newNode.next = current.next;
current.next = newNode;
}
function display(){
let currNode = this.head;
while(currNode.next !== null){
console.log(currNode.next.element);
corrNode = currNode.next;
}
}
function findPrev(e){
let currNode = this.head;
while(currNode.next !== null && currNode.next.element !== e){
currNode = currNode.next;
}
return currNode;
}
function remove(e){
let prev = this.findPrev(e);
if(prev.next !== null){
prev.next = prev.next.next;
}
}
複製代碼
這時,咱們能夠考慮實現一個雙向鏈表:code
按照上圖的理解:咱們先要給Node類增長一個先前鏈接的屬性function Node(element) {
this.element = element;
this.next = null;
this.previous = null;
}
複製代碼
咱們還要修改對應的insert方法,由於他如今須要創建兩個鏈接
function insert(newElement, item) {
var newNode = new Node(newElement);
var current = this.find(item);
newNode.next = current.next;
newNode.previous = current;
current.next = newNode;
}
複製代碼
雙向鏈表的remove()方法比單向鏈表的效率更高,由於不須要查找前驅節點了。
function remove(item) {
var currNode = this.find(item);
if (!(currNode.next == null)) {
currNode.previous.next = currNode.next;
currNode.next.previous = currNode.previous;
currNode.next = null;
currNode.previous = null;
}
}
複製代碼
function LList() {
this.head = new Node("head");
this.head.next = this.head; //讓頭結點的next指向它本身
this.find = find;
this.insert = insert;
this.display = display;
this.findPrevious = findPrevious;
this.remove = remove;
}
複製代碼
JavaScript中的Object類就是以字典形式設計的。因此字典的實現就像對象同樣,感受實在沒什麼值得寫的,這裏給一個demo。
function Dictionary(){
this.dataStore = new Array();
}
function add(key, value){
this.dataStore[key] = value;
}
function find(key){
return this.dataStore[key];
}
function remove(key){
delete this.dataStore[key]
}
function show(){
for( let key in Object.keys(this.dataStore)){
console.log(key + this.dataStore[key])
}
}
複製代碼