散列数据结构C++描述

本文进行两种散列的实现——线性开型寻址散列,链表散列

散列表——一种动态集合结构,它仅支持Insert,Search和Delete操作

基本规则:关键字key,index=fun(key),T[index]卫星数据,函数fun即散列函数。
查找一个元素的期望时间为O(1)

直接寻址表:关键字全域比较小,使用数组完全存储,一一对应。Insert,Search和Delete操作都是O(1)
散列表:关键字全域较大,可能出现碰撞。
解决碰撞之方法:
1)找到合适的散列函数。精心选择散列函数,并且仍然要解决可能出现的碰撞,该方法不太彻底。
2)链接法(实现)
给定一个能存放n个元素、具有m个槽位的散列表T,定义T的装载因子a=n/m,即一个链中平均存储的元素数。
任何元素散列到m个槽中每一个的可能性是相同的,且与其他元素已被散列到什么位置上是独立无关的。
这称为简单一致散列。一次成功查找为O(1+a),a=n/m,插入删除O(1),注a(书中为阿尔法)
3)开放寻址方法(例如线性开行寻址散列)
所有的元素都存放在散列表中,没有链表(即没有元素存放在散列表外),装载因子不大于1。
插入一个元素是,可以连续的检查散列表的各项,直到找到一个空槽来放置待插入的关键字时为止。


设计散列函数(算法设计略)
启发式方法:乘法散列和除法散列
随机化方法:全域散列

线性开型寻址散列实现
对散列表元素的删除操作执行起来比较困难;但可以解决,方法是:
删除槽i时,在将槽i的中设置一个特定的值DELETED,而不用NIL。当然相应的Hash-Search和Hash-Insert都要配合修改。
这样查找时间不依赖于装载因子a了。因此, 在必须删除关键字的应用中,往往采用链接法来解决碰撞。

以下实现的删除方法,是在下信手胡写,并不正确。
// file hash.h
#ifndef HashTable_
#define HashTable_

#include <iostream>
#include <stdlib.h>
#include "xcept.h"

using namespace std;
template<class E, class K>
class HashTable
{
   public:
      HashTable(int divisor = 11);
      ~HashTable() {delete [] ht; delete [] empty;}
      bool Search(const K& k, E& e) const;
      HashTable<E,K>& Insert(const E& e);
      HashTable<E,K>& Delete(E& e);
      void Output();// output the hash table
   private:
      int hSearch(const K& k) const;
      int D; // hash function divisor
      E *ht; // hash table array
      bool *empty; // 1D array
};

template<class E, class K>
HashTable<E,K>::HashTable(int divisor)
{// Constructor.
   D = divisor;

   // allocate hash table arrays
   ht = new E [D];
   empty = new bool [D];

   // set all buckets to empty
   for (int i = 0; i < D; i++)
      empty[i] = true;
}

template<class E, class K>
int HashTable<E,K>::hSearch(const K& k) const
{// Search an open addressed table.
 // Return location of k if present.
 // Otherwise return insert point if there is space.
   int i = k % D; // home bucket
   int j = i;     // start at home bucket
   do {
      if (empty[j] || ht[j] == k) return j;
      j = (j + 1) % D;  // next bucket
      } while (j != i); // returned to home?

   return j;  // table full
}

template<class E, class K>
bool HashTable<E,K>::Search(const K& k, E& e) const
{// Put element that matches k in e.
 // Return false if no match.
   int b = hSearch(k);
   if (empty[b] || ht[b] != k) return false;
   e = ht[b];
   return true;
}

template<class E, class K>
HashTable<E,K>& HashTable<E,K>::Insert(const E& e)
{// Hash table insert.
   K k = e; // extract key
   int b = hSearch(k);

   // check if insert is to be done
   if (empty[b]) {empty[b] = false;
                  ht[b] = e;
                  return *this;}

   // no insert, check if duplicate or full
   if (ht[b] == k) throw BadInput(); // duplicate
   throw NoMem(); // table full
}

template<class E, class K>
HashTable<E,K>& HashTable<E,K>::Delete(E& e)
{// Hash table insert.
   K k = e; // extract key
   int b = hSearch(k);

   // check if insert is to be done
   if (empty[b])
   {
       cout << "没有该元素。" << endl;
       return *this;
   }
   empty[b] = true;
   int count = 0;
   int index = b+1;
   while (index != b)
   {
       if (index >= D)
           index -= D;
       K key;
       if (!empty[index])
       {
           key = ht[index];
           if ((key % D) != index)
               count++;
       }
       index++;
   }
   cout << "count=" << count << endl;
   E *temp = new E[count];
   index = b+1;
   int i = 0;
   while (index != b)
   {
       if (index >= D)
           index -= D;
       K key;
       if (!empty[index] && i < count)
       {
           key = ht[index];
           if ((key % D) != index)
           {
               temp[i] = ht[index];
               empty[index] = true;
               i++;
           }
       }
       index++;
   }
   for (i = 0;i < count;i++)
       Insert(temp[i]);
   delete[] temp;
   return *this;
}
template<class E, class K>
void HashTable<E,K>::Output()
{
   for (int i = 0; i< D; i++) {
      if (empty[i]) cout << "empty" << endl;
      else cout << ht[i] << endl;}
}

#endif
xcept.h文件
// exception classes for various error types

#ifndef Xcept_
#define Xcept_

#include <new>

// bad initializers
class BadInitializers {
   public:
      BadInitializers() {}
};

// insufficient memory
class NoMem {
   public:
      NoMem() {}
};

// change new to throw NoMem instead of xalloc
void my_new_handler()
{
   throw NoMem();
};

//new_handler Old_Handler_ = set_new_handler(my_new_handler);
//set_new_handler(my_new_handler);
// improper array, find, insert, or delete index
// or deletion from empty structure
class OutOfBounds {
   public:
      OutOfBounds() {}
};

// use when operands should have matching size
class SizeMismatch {
   public:
      SizeMismatch() {}
};

// use when zero was expected
class MustBeZero {
   public:
      MustBeZero() {}
};
// use when zero was expected
class BadInput {
   public:
      BadInput() {}
};

#endif
hash.cpp测试实例
// test hash table with linear open addressing

#include <iostream>
#include "hash.h"

class element {
   friend int main(void);
   public:
      operator long() const {return key;}
//   private: g++ has a problem with main a friend
      int data;
      long key;
};

int main(void)
{
   HashTable<element, long> h(11);
   element e;
   e.key = 80;
   h.Insert(e);
   e.key = 40;
   h.Insert(e);
   e.key = 65;
   h.Insert(e);
   h.Output();
   e.key = 58;
   h.Insert(e);
   e.key = 24;
   h.Insert(e);
   cout << ' ' << endl;
   h.Output();
   e.key = 2;
   h.Insert(e);
   e.key = 13;
   h.Insert(e);
   e.key = 46;
   h.Insert(e);
   e.key = 16;
   h.Insert(e);
   e.key = 7;
   h.Insert(e);
   e.key = 21;
   h.Insert(e);
   cout << ' ' << endl;
   h.Output();
   e.key = 99;
 try {h.Insert(e);}
   catch (NoMem)
      {cout  << " No memory for 99" << endl;}
   cout << "delete 24" << endl;
   e.key = 24;
   h.Delete(e);
   h.Output();
   cout << "delete 15,there is not the element" << endl;
   e.key = 15;
   h.Delete(e);
   h.Output();
   e.key = 2;
   h.Delete(e);
   h.Output();
   return 0;
}
             
makefile文件
hash:hash.o hash.o xcept.h
        g++ -o hash hash.o
hash.o:hash.cpp hash.h xcept.h
        g++ -c hash.cpp hash.h xcept.h
        g++ -c hash.h
        g++ -c xcept.h
clean:
        rm -f hash *.o *.gch


输出结果:
empty
empty
empty
80
empty
empty
empty
40
empty
empty
65
 
empty
empty
24
80
58
empty
empty
40
empty
empty
65
 
7
21
24
80
58
2
13
40
46
16
65
 No memory for 99
delete 24
count=7
21
empty
2
80
58
13
46
40
16
7
65
delete 15,there is not the element
没有该元素。
21
empty
2
80
58
13
46
40
16
7
65
count=6
21
empty
13
80
58
46
16
40
7
empty
65



链接法实现














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值