Download presentation
Presentation is loading. Please wait.
Published byRagnvald Karlsen Modified 約 5 年前
1
酒居敬一(sakai.keiichi@kochi-tech.ac.jp)
アルゴリズムとデータ構造1 2007年7月6日
2
計算量の考察 キー値の比較を1回行うと候補は半減する ちょうど半分ずつ絞りこめばO(log N)
候補が半減する場合がもっとも効率が良い 半減するようにデータを保持する 例:平衡木を使う ちょうど半分ずつ絞りこめばO(log N) キーの比較という手法を使う限りはこれ以上探索の効率はよくならない。
3
比較に頼らない方法 ハッシュ法 データに関する情報を比較によらないで取得 データの性質が明らかであればO(1)に近づくことができる
ハッシュ関数が命 ハッシュ関数を設計するときに、データに関する情報を取得し盛り込む (連想記憶機構があれば…)
4
ハッシュテーブル (123ページ以降で詳しく) 並べたデータを「鍵」を用いてアクセス
「鍵」からハッシュテーブル内のデータを特定するための関数 → ハッシュ関数 ハッシュ関数 合同法(除算法) H(k) = k mod n (k: 鍵, n:素数) 平方抽出法 重ね合わせ法
5
ハッシュテーブルのイメージ データ
6
衝突 異なった鍵を用いてもハッシュ値が同じ 衝突を解決する方法 先に格納されているデータ → ホーム 後から格納するデータ → シノニム
先に格納されているデータ → ホーム 後から格納するデータ → シノニム 衝突を解決する方法 分離連鎖法 空き番地法
7
public class MyHashtable
{ private MyHashtable() } public MyHashtable(int aMaxSize) this.table = new AddressData[aMaxSize]; public AddressData get(String aKey) if(null == aKey){ throw new NullPointerException(); return this.table[this.calculateHashCode(aKey)]; public void printAll() for(int count = 0; count < this.table.length; count++){ System.out.println(count+1 + "\t" + this.table[count]); System.out.println(); private AddressData[] table;
8
public boolean put(AddressData anAddressData)
{ if(null == anAddressData){ return false; } this.table[this.calculateHashCode(anAddressData.getName())] = anAddressData; return true; public boolean remove(String aKey) if(null == aKey){ this.table[this.calculateHashCode(aKey)] = null; private int calculateHashCode(String aKey) throw new NullPointerException(); int intkey = 0; for(int count = 0; count < aKey.length(); count++){ intkey += 0xFFFF & aKey.charAt(count); return intkey % this.table.length; java MyHashtableTest 住所データを格納 null null null 杉山: 稲城,東京 208 null null ONGS Inc.: 渋谷,東京 151 後藤: 川崎,神奈川 214 null null 佐々木: 座間,神奈川 228 小澤: 多摩,東京 206 null null null null null null null
9
分離連鎖法(チェイン法) 連結リスト ハッシュ テーブル 図2.7.1 教科書125ページ
10
住所録として以下の項目を持つ 名前 市 都道府県 郵便番号 public class AddressData {
public AddressData(String aName, String aMetropolice, String aCity, String aZipcode) if((null == aName) || (null == aMetropolice) || (null == aCity)|| (null == aZipcode)){ throw new NullPointerException(); } this.name = aName; this.metropolice = aMetropolice; this.city = aCity; this.zipcode = aZipcode; public String getName() return this.name; public String getAddress() return this.city + "," + this.metropolice + " " + this.zipcode; public String toString() return this.name + ": " + this.city + "," + this.metropolice + “ " + this.zipcode; private String city; private String metropolice; private String name; private String zipcode; 住所録として以下の項目を持つ 名前 市 都道府県 郵便番号
11
public class ChainHashtable
{ private ChainHashtable() } public ChainHashtable(int aMaxSize) this.table = new MyLinkedList[aMaxSize]; private MyLinkedList[] table; public boolean put(AddressData anAddressData) { if(null == anAddressData){ return false; } int hashCode = this.calculateHashCode(anAddressData.getName()); if(null == this.table[hashCode]){ this.table[hashCode] = new MyLinkedList(); this.table[hashCode].insert(anAddressData); return true;
12
public AddressData get(String aKey)
{ if(null == aKey){ throw new NullPointerException(); } MyLinkedList list = this.table[this.calculateHashCode(aKey)]; if(null == list){ return null; int limit = list.size(); int count = 1; AddressData address = null; while(count <= limit){ address = (AddressData)list.get(count); if(address.getName().equals(aKey)){ return address; ++count; private int calculateHashCode(String aKey) { if(null == aKey){ throw new NullPointerException(); } int intkey = 0; for(int count = 0; count < aKey.length(); count++){ intkey += 0xFFFF & aKey.charAt(count); return intkey % this.table.length;
13
public boolean remove(String aKey)
{ if(null == aKey){ return false; } MyLinkedList list = this.table[this.calculateHashCode(aKey)]; if(null == list){ int limit = list.size(); int count = 1; AddressData address = null; while(count <= limit){ address = (AddressData)list.get(count); if(address.getName().equals(aKey)){ return list.remove(count); ++count; public void printAll() { for(int count = 0; count < this.table.length; count++){ if(null == this.table[count]){ System.out.println(this.table[count]); }else{ this.table[count].printAll(); } System.out.println();
14
ハッシュ表の大きさが3なので衝突が起きたときはリスト保持
java ChainHashtableTest 住所データを格納 杉山: 稲城,東京 208 佐々木: 座間,神奈川 228 → 小澤: 多摩,東京 206 ONGS Inc.: 渋谷,東京 151 → 後藤: 川崎,神奈川 214 データの取得: 後藤 後藤: 川崎,神奈川 214 データの削除: ONGS Inc. ハッシュ表の大きさが3なので衝突が起きたときはリスト保持
15
開番地法 キー 再ハッシュの方法 線形走査法 二重ハッシュ法 均一ハッシュ法 図2.7.4 教科書131ページ および教科書134ページ
既にデータが 格納されている ハッシュ キー 再ハッシュ 再ハッシュの方法 線形走査法 二重ハッシュ法 均一ハッシュ法 ここも既にデータが 格納されている 再ハッシュ この場所は空なので ここに格納する 図2.7.4 教科書131ページ および教科書134ページ
16
空き番地法を用いた場合の削除 キー 削除したい 削除 教科書134ページ ハッシュ 再ハッシュ 再ハッシュ 削除フラグを格納
同じハッシュ値だけど、これじゃない。 キー ハッシュ 再ハッシュ データは消えてるけど、これでもない。 削除したい 削除フラグ 削除フラグを格納 削除 再ハッシュ これだっ! このデータを 探索したい 教科書134ページ
17
1回目のハッシュは剰余演算 2回目以降は一定間隔離す 距離は前の値から1~3 1固定の場合は線形走査法と同じ
public class OpenAddressHashtable { public OpenAddressHashtable(int aMaxSize) this.table = new AddressData[aMaxSize]; } private final AddressData removedData = new AddressData("", "", "", ""); private AddressData[] table; private int calculateHashCode(String aKey) { if(null == aKey){throw new NullPointerException();} int intkey = 0; for(int count = 0; count < aKey.length(); count++){ intkey += 0xFFFF & aKey.charAt(count); } return intkey % this.table.length; 1回目のハッシュは剰余演算 2回目以降は一定間隔離す 距離は前の値から1~3 1固定の場合は線形走査法と同じ 固定値にしないときは二重ハッシュ法 private int calculateHashCodeAgain(String aKey, int aHashCode) { if(null == aKey){throw new NullPointerException();} int intkey = 0; for(int count = 0; count < aKey.length(); count++){ intkey += 0xFFFF & aKey.charAt(count); } int rehashCode = (aHashCode (intkey % 3)) % this.table.length; System.err.println("再ハッシュ: " + aKey + " " + aHashCode + “ → " + rehashCode); return rehashCode;
18
1回目のハッシュで衝突が起きたときは衝突が起きなくなるまで別のハッシュ関数でハッシュしなおす。
public boolean put(AddressData anAddressData) { if(null == anAddressData){ return false; } int hashCode = this.calculateHashCode(anAddressData.getName()); if((null == this.table[hashCode]) || (this.removedData == this.table[hashCode])){ this.table[hashCode] = anAddressData; return true; int limit = this.table.length -1; String key = anAddressData.getName(); for(int count = 0; count < limit; count++){ hashCode = this.calculateHashCodeAgain(key, hashCode); 1回目のハッシュで衝突が起きたときは衝突が起きなくなるまで別のハッシュ関数でハッシュしなおす。
19
public AddressData get(String aKey)
{ if(null == aKey){ throw new NullPointerException(); } int hashCode = this.calculateHashCode(aKey); if(null == this.table[hashCode]){ return null; if(this.removedData != this.table[hashCode]){ if(this.table[hashCode].getName().equals(aKey)){ return this.table[hashCode]; int limit = this.table.length -1; for(int count = 0; count < limit; count++){ hashCode = this.calculateHashCodeAgain(aKey, hashCode);
20
public boolean remove(String aKey)
{ if(null == aKey){ throw new NullPointerException();} int hashCode = this.calculateHashCode(aKey); if(null == this.table[hashCode]){ return false; } if(this.removedData != this.table[hashCode]){ if(this.table[hashCode].getName().equals(aKey)){ this.table[hashCode] = removedData; return true; int limit = this.table.length -1; for(int count = 0; count < limit; count++){ hashCode = this.calculateHashCodeAgain(aKey, hashCode);
21
ハッシュ表の大きさが5なので衝突が起きている
java OpenAddressHashtableTest null 住所データを格納 再ハッシュ: 後藤 1 → 2 再ハッシュ: 後藤 2 → 3 再ハッシュ: ONGS Inc. 1 → 2 再ハッシュ: ONGS Inc. 2 → 3 再ハッシュ: ONGS Inc. 3 → 4 佐々木: 座間,神奈川 228 杉山: 稲城,東京 208 小澤: 多摩,東京 206 後藤: 川崎,神奈川 214 ONGS Inc.: 渋谷,東京 151 データの削除: 杉山 データの削除: 小澤 データの削除: 後藤 再ハッシュ: 後藤 1 → 2 再ハッシュ: 後藤 2 → 3 データの削除: 佐々木 削除されました ONGS Inc.: 渋谷,東京 151 データの取得: ONGS Inc. 再ハッシュ: ONGS Inc. 1 → 2 再ハッシュ: ONGS Inc. 2 → 3 再ハッシュ: ONGS Inc. 3 → 4 ハッシュ表の大きさが5なので衝突が起きている
22
キー よくない二重ハッシュ法 配列サイズ10 ステップ幅5 +5 mod 10 ハッシュ 再ハッシュ 再ハッシュ 既にデータが
格納されている ハッシュ キー 配列サイズ10 ステップ幅5 +5 mod 10 再ハッシュ 再ハッシュ ここも既にデータが 格納されている よくない二重ハッシュ法
23
キー 二重ハッシュ法 配列サイズ11 ステップ幅5 +5 mod 11 ハッシュ 再ハッシュ 再ハッシュ 空きがあった! 既にデータが
格納されている ハッシュ キー 再ハッシュ 再ハッシュ 配列サイズ11 ステップ幅5 +5 mod 11 ここも既にデータが 格納されている 二重ハッシュ法
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.