第5章の演習


ソースのダウンロード

今後の演習では,ホームフォルダの下にmis2というフォルダを作って, そこで作業することを前提とする.作成していない時は,ターミナルから
mkdir ~/mis2
を実行する. http://opendatastructures.orgのc++ edition, c++ sources ( http://opendatastructures.org/ods-cpp.tgz ) からダウンロードしたファイルをホームフォルダの下のmis2に置く.ods.cpp.tgzというファイルができた時は,
cd ~/mis2
tar zxvf ods-cpp.tgz
ods-cpp.tarというファイルができた時は,
cd ~/mis2
tar xvf ods-cpp.tar
を実行するとcppというフォルダができる.Finderからダブルクリックしてもアーカイブユーティリティが立ち上がり展開されるので,そちらでも良い.
配付プログラムの ChainedHashTable.h は
template
void ChainedHashTable<T>::resize() {
	d = 1;
	while (1<<d <= n) d++;
    n = 0;
	array<List> newTable(1<<d);
	for (int i = 0; i < t.length; i++) {
		for (int j = 0; j < t[i].size(); j++) {
			T x = t[i].get(j);
			newTable[hash(x)].add(x);
		}
	}
	t = newTable;
}
のように'n = 0' という謎の1行が含まれている.
template
void ChainedHashTable<T>::resize() {
	d = 1;
	while (1<<d <= n) d++;
//    n = 0;
	array<List> newTable(1<<d);
	for (int i = 0; i < t.length; i++) {
		for (int j = 0; j < t[i].size(); j++) {
			T x = t[i].get(j);
			newTable[hash(x)].add(x);
		}
	}
	t = newTable;
}
のように,この行はコメントアウトして使うこと.

演習(ChangedHashTable)

~/mis2/cpp 以下にchainedHashTest.cpp というファイルを作成する.これは,エラトステネスのふるいを使って,1000までの素数の集合を求めるプログラムである.なお,1000までの素数を保持するためのデータ構造としては,ハッシュよりもboolの配列,あるいはビットベクターを用いた方が空間効率,時間効率が良いので,お勧めはしない. 
#include "ChainedHashTable.h"

int main(){
  ods::ChainedHashTable<int> primes;
  for(int i = 2; i < 1000; i++){
    primes.add(i);
  }
  // primes = {2,3,4,...,999}
  for(int i = 2; i < 1000; i++){
    if(primes.find(i) == i){
      std::cout << i << std::endl;
      for(int j = i + i; j < 1000; j += i) primes.remove(j);
    }
  }
  // primes = {2,3,5,7,11,...,997}
}
これを,
cd ~/mis2/cpp
g++-mp-4.9 -Wall  -o chainedHashTest chainedHashTest.cpp utils.cpp
でコンパイルし,
./chainedHashTest
で実行する.
(注) 配布プログラムのChainedHashTableの実装では,要素が含まれていない時に, は,ChainedHashTableのメンバ変数nullを返すが,これがprotectedで保護されて いるため,比較することができない(実装を見ると,INT_MINを代入しているの で(Tがint以外の場合はいろいろと困ったことになるはず),これと比較すること は可能だが).上のプログラムでは,find(i)の結果がiの時は要素が含まれていると判断しているが,iがINT_MINの時には判断できない.

演習(LinearHashTable)

~/mis2/cpp 以下にlinearHashTest.cpp というファイルを 作成する.
#include "utils.h"
#include "LinearHashTable.h"

int main(){
  const int null = -1;
  const int del = -2;
  ods::LinearHashTable<int> primes(null, del);
  for(int i = 2; i < 1000; i++){
    primes.add(i);
  }
  // primes = {2,3,4,...,999}
  for(int i = 2; i < 1000; i++){
    if(primes.find(i) != null){
      std::cout << i << std::endl;
      for(int j = i + i; j < 1000; j += i) primes.remove(j);
    }
  }
  // primes = {2,3,5,7,11,...,997}
}
これを,
cd ~/mis2/cpp
g++-mp-4.9 -Wall  -o linearHashTest linearHashTest.cpp LinearHashTable.cpp utils.cpp
でコンパイルし,
./linearHashTest
で実行する.
(注) 配布プログラムのLinearHashTableの実装では,型Tの中で明示的にnull, del に使う値を指定することができるようになっている.上のプログラムでは,要素がすべて正であることを利用して,nullを-1, delを-2にしている.
このプログラムを改造して,1000以下の素数の数を求めなさい.1000以下の素数はいくつになるか?
  1. 89
  2. 168
  3. 230
  4. 231
  5. 1000