⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hashfm.txt

📁 一本数据结构的经典书籍-数据结构算法程序集里
💻 TXT
📖 第 1 页 / 共 2 页
字号:
//散列文件的插入、删除和查找操作
//HashFM.cpp
#include<iostream.h>
#include<stdlib.h>
#include<fstream.h>
#include<iomanip.h>
//m为散列表的长度,确定取值为16
  const int m=16;  
//km为散列主文件中每个结点所含的元素个数,
//取值大于等于1,暂取为3
  const int km=3;  
//定义关键字类型为整型
  typedef int KeyType;
//索引主文件中的记录元素类型
struct ElemType {
 int key;    //关键字域
 char rest[10];//其他域,暂用字符数组表示
};
//索引主文件中的结点类型
struct FLNode {
  ElemType data[km];//值域
  int next; //指向下一个结点的指针域
};
//b1为索引表文件中的记录长度
  const int b1=sizeof(int);
//b2为索引主文件中的记录长度
  const int b2=sizeof(FLNode); 
//NullTag作为空关键字的标记,假定用-10表示
  const int NullTag=-10;
//散列文件的类定义
template<class T>
class HFile
{public:
  //构造函数,初始化散列表文件和主文件
  HFile(char* fn1,char* fn2);
  //把元素x插入到按桶散列的文件中
  void THFInsertA(char* fn1,char* fn2,T x);
  //把数组x中n个元素插入到按桶散列的文件中
  void THFInsertB(char* fn1,char* fn2,T x[],int n);
  //从按桶散列的文件中删除关键字为x.key的元素,
  //并由x带回该元素,若删除成功则返回1,否则返回0
  bool THFDelete(char* fn1, char* fn2, T& x);
  //从按桶散列的文件中查找关键字为x.key的元素,
  //并由x带回该元素,若查找成功则返回1,否则返回0
  bool THFSearch(char* fn1,char* fn2,T& x);
  //按单链表顺序打印出按桶散列主文件中每个结点的所有元素值
  void THFPrint(char* fn1,char* fn2);
};
//散列文件的类实现
//初始化散列表文件和主文件
template<class T>
HFile<T>::HFile(char* fn1,char* fn2)
{//以输出方式打开并建立空的散列表文件
 ofstream f1(fn1, ios::out|ios::binary);
 if(!f1) {
   cerr<<fn1<<' '<<"不能打开!"<<endl;
   exit(1);}
//以输出方式打开并建立空的散列主文件
 ofstream f2(fn2, ios::out|ios::binary);
 if(!f2) {cerr<<fn2<<' '<<"不能打开!"<<endl;
	  exit(1);}
//动态分配具有m+1个整型存储空间的数组A
 int* A=new int[m+1];
 if(!A){cerr<<"申请堆内存失败!"<<endl;
       	exit(1);}
//给数组A中的每个元素赋初值-1,表示空指针
 for(int i=0; i<m+1; i++)
   A[i]=-1;
//初始化散列表文件
  f1.write((char*)A, (m+1)*b1);
 //删除数组A并关闭文件
  delete [] A;
  f1.close();
  f2.close();
}
//把元素x插入到按桶散列的文件中
template<class T>
void HFile<T>::THFInsertA(char* fn1, char* fn2, T x)
{//以输入输出和不新建方式打开散列表文件
 fstream f1(fn1,ios::in|ios::out|ios::binary);
 if(!f1) {cerr<<fn1<<' '<<"不能打开!"<<endl;
      exit(1);}
 //以输入输出和不新建方式打开散列主文件
 fstream f2(fn2, ios::in|ios::out|ios::binary);
 if(!f2){cerr<<fn2<<' '<<"不能打开!"<<endl;
         exit(1);}
 //给数组A中的每个元素赋初值-1,表示空指针
 int* A=new int[m+1];
 if(!A) {cerr<<"申请堆内存失败!"<<endl;
	 exit(1);}
 //将散列表文件中的内容全部读入到数组A中
 f1.read((char*)A, (m+1)*b1);
 //以关键字x.key计算x的散列地址
 int d=x.key%m;
 //将x插入到d单链表的表头结点中
 int j;
 FLNode temp;
 if(A[d]!=-1)
  {f2.seekg(A[d]*b2);
   f2.read((char*)&temp, b2);
   for(j=0; j<km; j++)
    if(temp.data[j].key==NullTag) break;
    if(j<km) {
      temp.data[j]=x;
      f2.seekg(-b2, ios::cur);
      f2.write((char*)&temp, b2);
      goto END;  //插入表头结点后,转去做结束处理
  }}
  //当d单链表为空或头结点中没有空闲位置时向下执行
  //建立待插入d单链表表头的内存结点temp
  temp.data[0]=x;
  for(j=1; j<km; j++)
   temp.data[j].key=NullTag;
  temp.next=A[d];
  //将temp结点的值写入到f2文件尾并被链接到d单链表的表头
  if(A[m]==-1) {
  //将f2中的文件指针移至文件尾
   f2.seekg(0,ios::end);
  //计算出文件尾的结点位置序号
   int len=f2.tellg()/b2;
  //将temp结点的值写入文件尾
   f2.write((char*)&temp,b2);
  //使A[d]指向新插入的结点
   A[d]=len;}
  //将temp结点的值写入到f2文件的一个空闲结点中
  //并被链接到d单链表的表头
   else {//p指向空闲单链表的表头结点
     int p=A[m];
   //使空闲单链表的表头指针指向其下一个结点
     f2.seekg(p*b2);
     FLNode pn;
     f2.read((char*)&pn, b2);
     A[m]=pn.next;
   //使temp的值写入到p位置的结点上
     f2.seekg(-b2, ios::cur);
     f2.write((char*)&temp, b2);
   //使A[d]指向新插入的p结点
     A[d]=p;}
  //将数组A中的全部内容写回到散列表文件f1中
   f1.seekg(0);
   f1.write((char*)A, (m+1)*b1);
  //删除动态数组A和关闭所有文件
   END:
    delete [] A;
    f1.close();
    f2.close();
}
//把数组x中n个元素插入到按桶散列的文件中
template<class T>
void HFile<T>::THFInsertB(char* fn1,char* fn2,T x[],int n)
{fstream f1(fn1, ios::in|ios::out|ios::binary);
 if(!f1) {cerr<<fn1<<' '<<"不能打开!"<<endl;
	  exit(1);}
 fstream f2(fn2, ios::in|ios::out|ios::binary);
 if(!f2) {cerr<<fn2<<' '<<"不能打开!"<<endl;
          exit(1);}
 int* A=new int[m+1];
 if(!A) {cerr<<"申请堆内存失败!"<<endl;
	 exit(1);}
 f1.read((char*)A, (m+1)*b1);
 for(int i=0; i<n; i++)
  {int d=x[i].key%m;
   int j;
   FLNode temp;
   if(A[d]!=-1)
    {f2.seekg(A[d]*b2);
     f2.read((char*)&temp, b2);
     for(j=0; j<km; j++)
      if(temp.data[j].key==NullTag) break;
      if(j<km) {
       temp.data[j]=x[i];
       f2.seekg(-b2, ios::cur);
       f2.write((char*)&temp, b2);
       continue;}}
      temp.data[0]=x[i];
      for(j=1;j<km;j++)
	temp.data[j].key=NullTag;
      temp.next=A[d];
      if(A[m]==-1) {
       f2.seekg(0,ios::end);
       int len=f2.tellg()/b2;
       f2.write((char*)&temp,b2);
       A[d]=len;}
      else {int p=A[m];
	f2.seekg(p*b2);
	FLNode pn;
	f2.read((char*)&pn, b2);
	A[m]=pn.next;
	f2.seekg(-b2, ios::cur);
	f2.write((char*)&temp, b2);
	A[d]=p;}}
    f1.seekg(0);
    f1.write((char*)A, (m+1)*b1);
    delete [] A;
    f1.close();f2.close();
}
//从按桶散列的文件中删除关键字为x.key的元素,并由x带回该
//元素,若删除成功则返回1,否则返回0
template<class T>
bool HFile<T>::THFDelete(char* fn1,char* fn2,T& x)
{fstream f1(fn1,ios::in|ios::out|ios::binary);
 int k;
 if(!f1) {cerr<<fn1<<' '<<"不能打开!"<<endl;
	  exit(1);}
 fstream f2(fn2,ios::in|ios::out|ios::binary);
 if(!f2) {cerr<<fn2<<' '<<"不能打开!"<<endl;
	  exit(1);}
 int* A=new int[m+1];
 if(!A) {cerr<<"申请堆内存失败!"<<endl;
	 exit(1);}
 f1.read((char*)A, (m+1)*b1);
 int DeleteTag=0;  //用DeleteTag作为删除是否成功的标记
 int d=x.key%m;
 int p=A[d],i=0;  //用p保存d单链表的表头结点的位置序号,
 //用i保存该结点中被删除元素的下标或第一个空元素的下标
 FLNode temp;
 //从d单链表的表头结点中删除关键字为x.key的元素
 if(p!=-1)
  {f2.seekg(p*b2);
   f2.read((char*)&temp, b2);
   while(i<km && temp.data[i].key!=NullTag)
    if(temp.data[i].key==x.key) break;
    else i++;
    if(i<km && temp.data[i].key==x.key) {
     x=temp.data[i]; //由x带回被删除的元素值
    for(k=i+1; k<km; k++)
     if(temp.data[k].key!=NullTag)
       temp.data[k-1]=temp.data[k];
     else break;
   temp.data[k-1].key=NullTag;
   if(k-1==0) { //删除d单链表中表头空结点
    A[d]=temp.next;
    temp.next=A[m];
    A[m]=p;}
    f2.seekg(-b2, ios::cur);
    f2.write((char*)&temp, b2);
    DeleteTag=1;//被赋值1表示删除成功
    goto END;  //转去做结束处理
  }}
 //若d单链表为空,则转去做结束处理
  else goto END;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -