數據結構的JavaScript實現

1、數組

2、棧

棧是一種聽從後進先出原則的有序集合。新添加的或待刪除的元素都保存在棧的末尾,稱做棧頂,另外一端叫作棧底。在棧裏,新元素都靠近棧頂,舊元素都接近棧底。node

class Stack{
    constructor(){
        this.item = []
    }
    push(element){
        this.item.push(element)
    }
    pop(){
        return this.item.pop()
    }
    peek(){
        return this.item[this.item.length-1]
    }
    isEmpty(){
        return this.item.length === 0
    }
    size(){
        return this.item.length
    }
    clear(){
        this.item = []
    }
    print(){
        console.log(item.toString())
    }
}
複製代碼

3、隊列

隊列是一種遵循先進先出原則的一組有序的項。隊列在尾部添加元素,並從頂部移除元素。最新添加的元素必須排在隊列的末尾。數組

class Queue{
    constructor(){
        this.item = []
    }
    enqueue(element){
        this.item.push(element)
    }
    dequeue(){
        return this.item.shift()
    }
    front(){
        return this.item[0]
    }
    isEmpty(){
        return this.item.length === 0
    }
    clear(){
        this.items = []
    }
    size(){
        return this.item.length
    }
}
複製代碼

4、鏈表

鏈表儲存有序的元素集合,但不一樣於數組,鏈表的每一個元素由一個儲存元素自己的節點和一個指向下一個元素的引用組成。bash

1. 單向鏈表

節點只有鏈向下一個節點的連接。 數據結構

Markdown

class Node{
    constructor(element){
        this.element = element
        this.next = null
    }
}
class LinkedList{
    constructor(){
        this.length = 0
        this.head = null
    }
    
/********末尾插入元素********/
    append(element){
        let node = new Node(element),current
        if(this.head === null){
            this.head = node
        }else{
            current = this.head
            while(current.next){
                current = current.next
            }
            current.next = node
        }
        this.length++
    }

/********指定位置插入元素********/
    insert(position, element){
        if(position>=0 && position<this.length){
            let node = new Node(element)
            let current = this.head
            let previous
            let index = 0
            if(position ===0 ){
                current.next = current
                current = node
            }else{
                while(index++ < position){
                    previous = current
                    current = current.next
                }
                node.next = current
                previous.next = node
            }
            length++
            return true
        }else{
            return false
        }
    }

/********指定位置刪除元素********/
    removeAt(position){
        if(position>=0 && position<this.length){
            let current = this.head
            let previous
            let index = 0
            if(position ===0 ){
               this.head = current.next
            }else{
                while(index++ < position){
                    previous = current
                    current = current.next
                }
                previous.next = current.next
            }
            length--
            return current.element
        }else{
            return null
        }
    }

/********指定值刪除元素********/
    remove(element){
        let index = this.indexOf(element)
        return this.removeAt(index)
    }

/********將鏈表轉換成一個字符串********/
    toString(){
        let current = this.head
        let string = ""
        while(current){
            string += current.element + (current.next ? ">" : "")
            current = current.next
        }
        return string
    }
/********在鏈表中查找元素的位置********/
    indexOf(element){
        let current = this.head
        index = 0
        while(current){
            if(element === current.element){
                return index
            }
            index++
            current = current.next
        }
        return -1
    }
    
    isEmpty(){
        return this.length === 0    
    }
    
    size(){
        return this.length
    }
    
    getHead(){
        return this.head
    }
}
複製代碼

2. 雙向鏈表

節點的連接是雙向的,一個鏈向下一個元素,另外一個鏈向前一個元素。 app

Markdown

class Node{
    constructor(element){
        this.element = element
        this.next = null
        this.prev = null
    }
}
class DoublyLinkedList{
    constructor(){
        this.length = 0
        this.head = null
        this.tail = null
    }
    insert(position, element){
        if(position>=0 && position<this.length){
            let node = new Node(element)
            let current = this.head
            let previous
            let index = 0
            if(position === 0){
                if(!this.head){
                    this.head = node
                    this.tail = node
                }else{
                    node.next = current
                    current.prev = node
                    this.head = node
                }
            }else if(position === this.length){
                current = this.tail
                current.next = node
                node.prev = current
                tail = node
            }else{
                while(index++ < position){
                    previous = current
                    current = current.next
                }
                node.next = current
                previous.next = node
                
                current.prev = node
                node.prev = previous
            }
            length++
            return true
        }else{
            return false
        }
    }
    removeAt(position){
        if(position>=0 && position<this.length){
            let current = this.head
            let previous
            let index = 0
            if(position ===0 ){
               this.head = current.next
               if(this.length === 1){
                   tail = null
               }else{
                   head.prev = null
               }
            }else if(position === this.length-1){
               current = tail
               tail = current.prev
               tail.next = null
            }else{
                while(index++ < position){
                    previous = current
                    current = current.next
                }
                previous.next = current.next
                current.next.prev = previous
            }
            length--
            return current.element
        }else{
            return null
        }
    }
}
複製代碼

3. 循環鏈表

最後一個元素指向下一個元素的指針不是引用null,而是指向第一個元素head。 ui

Markdown

4. 雙向循環鏈表

有指向head元素的tail.next,和指向tail元素的head.prev。 this

Markdown

5、集合

無序且惟一的項,以值-值形式儲存元素。spa

class Set{
    constructor(){
        this.items = {}
    }
    has(value){
        return value in this.items
    }
    add(value){
    
        if(!this.has(value)){
            this.items[value]=value
            return true
        }
        else{
            return false
        }
    }
    remove(){
        if(this.has(value)){
            delete this.items[value]
            return true
        }
        else{
            return false
        }
    }
    clear(){
        this.items = {}
    }
    size(){
        return Object.keys(this.items).length
    }
    values(){
        let values = []
        for(let i=0,keys=Object.keys(this.items); i<keys.length; i++){
            values.push(this.items[keys[i]])
        }
        return values
    }
}
複製代碼

6、字典和散列表

(一)字典

以鍵-值形式儲存元素,以遍歷整個數據結構的方式獲取值。指針

class Dictionary{
    constructor(){
        this.items = {}
    }
    has(key){
        return key in this.items
    }
    set(key, value){
        item[key] = value
    }
    delete(key){
        if(this.has(key)){
            delete this.items[key]
            return true
        }
        else{
            return false
        }
    }
    get(key){
        return this.has[key] ? items[key] : undefined    
    }
    values(){
        let values = []
        for(var k in items){
            if(this.has(k)){
                values.push(items[key])
            }
        }
        return values
    }
    keys(){
        return Object.keys(items)
    }
    getItems(){
        return items
    }
    clear(){
        this.items = {}
    }
    size(){
        return Object.keys(this.items).length
    }
}
複製代碼

(二)散列表(哈希表)

以鍵-值形式儲存元素,可以知道值的具體位置,所以可以快速檢索到該值。code

衝突版:將 key 的每一個字符的 Unicode 碼值的和加到 hash 變量中,hash會有衝突。

class HashTable{
    constructor(){
        this.table = []
    }
    loseloseHashCode(key){
        let hash = 0
        for(let i = 0; i<key.length; i++){
            hash += key.charCodeAt(i)
        }
        return hash % 37
    }
    put(key, value){
        let position = this.loseloseHashCode(key)
        console.log(position + ":" + key)
        table[position] = value
    }
    get(key){
        return table[loseloseHashCode(key)]
    }
    remove(key){
        table[loseloseHashCode(key)] = undefined
    }
}
複製代碼

解決衝突版:分離連接,爲散列表的每個位置建立一個鏈表並將元素存儲在裏面。

Markdown

class valuePair{
    constructor(key, value){
        this.key = key
        this.value = value
    }
    toString(){
        return `[${this.key} - ${this.value}]`
    }
}
class HashTable{
    constructor(){
        this.table = []
    }
    loseloseHashCode(key){
        let hash = 0
        for(let i = 0; i<key.length; i++){
            hash += key.charCodeAt(i)
        }
        return hash % 37
    }
    put(key, value){
        let position = this.loseloseHashCode(key)
        if(table[position] === undefined){
            table[position] = new LinkedList()
        }
        table[position].append(new ValuePair(key, value))
    }
    get(key){
        return table[loseloseHashCode(key)]
    }
    remove(key){
        table[loseloseHashCode(key)] = undefined
    }
}
複製代碼
相關文章
相關標籤/搜索