1. 程式人生 > >js--數據結構之散列

js--數據結構之散列

數組實現 dex numbers 時有 分布 ota key html 字符串

散列:實現散列表的數據後可以快速地實現插入或者刪除。但是對於實現查找操作則效率非常的低。
散列表的底層是數組實現的,長度是預先設定,可以隨時根據需求增加。所有的元素根據和該元素對應的鍵,保存在特定的位置。使用散列表存儲數據時,通過一個散列函數將鍵值映射為一個數字,數字的範圍是0-散列表的長度。
碰撞(collision):理想狀態下散列函數會將每一個鍵值映射成一個唯一的數組索引。但是健的數量是無限的,數組的長度是有限的,一個更現實的目標是讓散列函數盡量將鍵均勻地映射到數組中。即使使用一個高效的散列函數,仍然存在兩個鍵映射成同一個值的可能。這就是所謂的碰撞。它產生時我們就要去解決。
散列表中的數組究竟設置多大?
常見設置:數組長度是一個質數。
        function HashTable() {
                this.table = new Array(137);
                this.simpleHash = simpleHash;//哈希函數
                this.betterHash = betterHash;//霍納哈希函數
                this.buildChains = buildChains;//開連法
                this.showDistro = showDistro;//顯示散列表中的數據
                this
.showDistro1 = showDistro1;//開連法顯示散列表中的數據 this.put = put;//將數據存儲到列表中 //this.newPut = newPut;//將數據存儲到列表中 this.get = get; } //哈希函數:簡單的除留余數法 function simpleHash(data) { var total = 0; for(var i = 0;i<data.length;i++) { total
+= data.charCodeAt(i);//方法可返回指定位置的字符的Unicode 編碼。這個返回值是0-65535之間的整數。相加得到散列值。 } //console.log(total+"======"); return total%this.table.length;//除留余數法返回一個數值 } function put(data) { var _pos = this.simpleHash(data);//的到數組的索引 //var _pos = this.betterHash(data);//的到數組的索引 this.table[_pos] = data;//根據返回的值作為鍵值存儲數據。 } function showDistro() { //var n = 0; for(var i = 0;i < this.table.length;i++) { if(this.table[i] != undefined) { console.log(i+": "+this.table[i]); //document.write(i+": "+this.table[i]+"<br>"); } } } var hash = new HashTable(); var book = ["JavaScript","jQuery","php","java","go","html5","AI"]; for(var i =0;i < book.length;i++) { hash.put(book[i]); } //hash.showDistro(); console.log(book.length);
1: AI
7: java
54: php
56: JavaScript
77: go
79: html5
92: jQuery
上述會有問題:
1.數據呈現向兩端分布。
2.有時會出現內容顯示不全的問題,(散列函數處理時有了相同的散列值,就產生了碰撞)
散列函數的設計:解決碰撞
確保散列表用來存儲數據的數組其大小是一個質數(數學運算對質數取余數時余數重復率低)。數組的長度應該大於100,讓其分布更加的均勻。
霍納算法:
新的散列函數仍然先用計算字符串的ASCII碼值,不過在求和時每次乘以一個質數。建議一個較小的,(31,37);
        function betterHash(str) {
                var h = 37;
                var total = 0;
                for(var i = 0;i < str.length;i++) {
                    total += h*total+str.charCodeAt(i);
                }
                total = total % this.table.length;
                if(total < 0) {
                    total += this.table.length - 1;
                }
                return parseInt(total);
            }
            var hash2 = new HashTable();
            var book2 = ["JavaScript","jQuery","php","java","go","html5","AI"];
            for(var i = 0;i < book2.length;i++) {
                hash2.put(book2[i]);
            }
散列化整型鍵:
上述兩個例子都是對於字符串類型的鍵值進行操作,現在研究整型鍵的數據操作。
eg:學生的成績查詢,隨機生成一個9位數的鍵(ID),用以識別學生身份和一門成績。
        //生成學生成績:
            function getRandomGrade(min,max) {
                return Math.floor(Math.random()*(max-min+1))+min;
            }
            //生成ID:
            function getStuID(arr) {
                for(var i = 0;i < arr.length;i++) {
                    var num = "";
                    for(var j = 0;j < 9;j++) {
                        num +=Math.floor(Math.random()*10);
                    }
                    num += getRandomGrade(50,100);
                    arr[i] = num;
                }
            }
            var stuNum = 10;
            var students = new Array(stuNum);
            getStuID(students);
            for(var i = 0;i < students.length;i++) {
                //console.log(students[i]);
                console.log(students[i].substring(0,8)+" "+students[i].substring(9));
            }
            var hTab = new HashTable();
            for(var i = 0;i < students.length;i++) {
                hTab.put(students[i]);
            }
            hTab.showDistro();
            //如果同樣用第一種哈希函數解決會產生碰撞,用較好的哈希函數則不會產生碰撞。    
           //散列表的排序,取值:
           // 要重新定義put(),get();
           
            //帶有鍵值的添加方法
            function newPut(key,data) {
                var _pos = this.betterHash(key);
                this.table[_pos] = data;
            }
            //獲取方法:
            function get(key) {
                return this.table[this.betterHash(key)];
            }
            //test: 輸入三個人的姓名和電話號碼進行查詢,三個輸入後輸出quit進行查詢
            var numbers = new HashTable();
            var name,number;
            for(var i = 0;i < 3;i++) {
                //name = prompt("請輸入姓名:");
                //number = prompt("請輸入電話:");
                numbers.newPut(name,number);
            }
            name = "";
            prompt("輸入quit結束:");
            while(name != "quit") {
                name = prompt("裏面的成員:");
                if(name == "quit") {
                    break;
                }
                alert(name+"成員的電話是:" + numbers.get(name));
                prompt("輸入quit結束:");
            }
碰撞處理:開鏈法和線性檢測
開鏈法:將鍵同樣存儲到通過散列函數計算的索引位置上,但不可能將多份數據存儲到一個數組單元中。在實現散列表的底層數組中的每一個元素又是一個新的數據結構,即使使用兩個鍵三列後的值相同,依然被保存在同樣的位置,但是他們在第二個數組的位置不一樣。
實現方法:在創建存儲散列的鍵值的數組時通過調用一個函數創建一個空數組,然後將該數組賦值給散列表中的每個數組。這樣就創建了一個二維數組。
        function buildChains() {
                for(var i = 0;i < this.table.length;i++) {
                    this.table[i] = new Array();
                }
            }
            //相應的顯示元素也要改變
            function showDistro1() {
                //var num = 0;
                for(var i = 0;i < this.table.length;i++) {
                    if(this.table[i][0] != undefined) {
                        console.log(i + ":" +this.table[i]);
                    }
                }
            }
            //put
            function put(key,data) {
                var pos = this.simpleHash(key);
                var index = 0;
                if(this.table[pos][index] == undefined) {
                    this.table[pos][index] = data;
                }else {
                    while(this.table[pos][index] != undefined) {
                        ++index;
                    }
                    this.table[pos][index] = data;
                }
            }
            //get
            function get(key) {
                var index = 0;
                var pos = this.simpleHash(key);
                if(this.table[pos][index] == key) {
                    return this.table[pos][index];
                }else {
                    while(this.table[pos][index] != key) {
                        ++index;
                    }
                    return this.table[pos][index];
                }
                return undefined;
            }
            //test:
            var hTable = new HashTable();
            hTable.buildChains();
            var arrName = ["David","Jennifer","Donnie","Raymond","Cynthia","Mike","Clayton","Danny","Jonathan"];
            for(var i = 0;i < arrName.length;i++) {
                hTable.put(arrName[i]);
            }
            hTable.showDistro1();    

js--數據結構之散列