数据结构课设——散列文件的插入、删除和查找

题目

功能要求:
(1)初始化散列文件;
(2)向散列文件中插入一个元素;
(3)从散列文件中删除一个元素;
(4)从散列文件中查找一个元素。
散列文件通常采用链接法处理冲突。
散列文件中每个节点的类型定义为:

Struct FLNode  
{  //散列主文件中的节点类型
       ElemType data  ;  //值域
       int next;  //指向下一个节点的指针域
};

代码

#include <bits/stdc++.h>
using namespace std;

const int N=20; //以去留余数法创建散列表
typedef int KeyType;
struct Elemtype
{
    KeyType key; //存储关键信息
    char rest[N]; //存储附加信息
};
struct FLNode
{
    Elemtype data; //值域
    int next; //指针域
};
char filename[]="Hash"; // 散列主文件名
char Iname[]="HashIndex"; // 索引文件名
const int b1 = sizeof(KeyType); //索引表文件中的元素长度
const int b2 = sizeof(struct FLNode);   //索引主文件中的结点长度

void welcome(); //欢迎使用
int start(); //模式选择函数
void existHash(char *fname); //检测是否存在散列文件
void InitHashFile(char *fname); //初始化散列文件
void HashFilePrint(char *fname); //打印散列文件
void HashFileInsert(char filename[]); //插入一个元素
bool HashFileSearch(char *fname,struct Elemtype *x); //在散列文件中查找元素并返回查找结果
void HashFileInOne(char *fname,struct Elemtype x); //向散列文件中插入一个元素
void HashSearch(char *fname); //查找一个元素
bool HashDelete(char *fname,struct Elemtype *x); //在散列表中删除一个元素
void HashFileDelete(char *fname); //删除一个元素
int main()
{
    welcome();
    while(1)
    {
        int choose=start();
        if(choose==0) break;
        else if(choose==1) InitHashFile(filename); //进行初始化操作
        else if(choose==5) HashFilePrint(filename); //打印散列文件
        else if(choose==2) HashFileInsert(filename);  //向散列文件中插入一个元素
        else if(choose==4) HashSearch(filename); //查找一个元素
        else if(choose==3) HashFileDelete(filename); //删除一个元素
        else cout<<"您输入的指令有误,请重新输入!"<<endl<<endl;
    }
    cout<<"****已退出系统,感谢您的使用!****"<<endl<<endl;
    return 0;
}
bool HashDelete(char *fname,struct Elemtype *x) //在散列表中删除一个元素
{
    FILE *fp1, *fp2;
    fp1 = fopen(fname, "rb+");
    fp2 = fopen(Iname, "rb+");
    if(NULL == fp1|| NULL == fp2)
    {
        printf("打开文件失败!\n");
        exit(1);
    }
    int *A;
    A = (int *)calloc(N+1, b1);
    if(NULL == A)
    {
        printf("内存申请失败!\n");
        exit(1);
    }
    fread((char *)A, (N+1)*b1, 1, fp2);
    int d = x->key % N;
    int p = A[d],q;
    struct FLNode tp,tq;
    while(-1 != p)
    {
        fseek(fp1, (N+1)*b1+p*b2, 0);
        fread((char*)&tp, b2, 1, fp1);
        if(tp.data.key  == x->key)
        {
            //被删除结点的元素值赋给x带回
            *x = tp.data;
            //从单链表中删除p结点
            if(p == A[d])
                A[d] = tp.next;
            else
            {
                tq.next = tp.next;
                fseek(fp1, (N+1)*b1+q*b2, 0);
                fwrite((char *)&tq, b2, 1, fp1);
            }
            //将p结点连接到空闲单链表的表头
            tp.next = A[N];
            fseek(fp1, (N+1)*b1+p*b2, 0);
            fwrite((char *)&tp, b2, 1,fp1);
            A[N] = p;
            //结束while循环
            break;
        }
        else
        {
            //使p指针的值赋给q,tp结点的值赋值给tq结点
            q = p;
            tq = tp;
            //p指向单链表中的下一个结点
            p = tp.next;
        }//if分支结束
    }//while循环结束
    //将索引文件的表头重新写入索引文件
    fseek(fp1, 0L, 0);
    fseek(fp2, 0L, 0);
    fwrite((char *)A, (N + 1) * b1, 1, fp2);
    //释放A数组申请的内存空间
    free(A);
    //关闭散列文件
    fclose(fp1);
    fclose(fp2);
    if(-1 == p)
        return false;
    else
        return true;
}
void HashFileDelete(char *fname) //删除一个元素
{
    struct Elemtype x;
    cout<<"请输入待删除元素的关键信息(序号):";
    cin>>x.key;
    cout<<endl;
    if(!HashFileSearch(filename,&x)) cout<<"该元素在散列文件中不存在,不需要删除"<<endl<<endl;
    else
    {
        bool mark=HashDelete(filename,&x);
        if(mark==1) cout<<"关键元素(序号)为"<<x.key<<"的元素删除成功"<<endl<<endl;
        else cout<<"关键元素(序号)为"<<x.key<<"的元素删除失败"<<endl<<endl;
    }
}
void HashSearch(char *fname) //查找一个元素
{
    struct Elemtype x;
    cout<<"请输入待插入元素的关键信息(序号):";
    cin>>x.key;
    cout<<endl;
    if(HashFileSearch(filename,&x)) cout<<"该元素在散列文件中存在"<<endl<<endl;
    else cout<<"该元素在散列文件中不存在"<<endl<<endl;
}
void HashFileInOne(char *fname,struct Elemtype x) //向散列文件中插入一个元素
{
    FILE *fp1, *fp2;
    fp1 = fopen(fname, "rb+");
    fp2 = fopen(Iname, "rb+");
    if(NULL == fp1)
    {
        printf("打开文件失败!\n");
        exit(1);
    }
    int *A;
    A = (int *)calloc(N + 1, b1);
    if(!A)
    {
        printf("内存申请失败!\n");
        exit(1);
    }
    fread((char *)A, (N + 1) * b1, 1, fp2);
    int d = x.key % N;
    //以x和A[d]的值构成待插入散列文件的内存节点temp
    struct FLNode temp,pn;
    temp.data = x;
    temp.next = A[d];
    //将temp结点的值写入到散列文件中,并链接到散列文件表头
    //下表d单链表的表头
    int p,len;
    if(-1 == A[N])
    {
        //将文件指针移至文件尾
        fseek(fp1, 0L, 2);
        //计算出文件尾的结点位置序号
        len = (ftell(fp1) - (N+1)*b1)/b2;
        //将temp结点的值写入文件尾
        fwrite((char *)&temp, b2, 1, fp1);
        //使A[d]指向新插入的结点
        A[d] = len;
    }
    else
    {
        //p指向空闲单链表的表头结点
        p = A[N];
        //使空闲单链表的表头指针指向其下一个结点
        fseek(fp1, b1 * (N+1) + p*b2, 0);
        fread((char *)&pn, b2, 1, fp1);
        A[N] = pn.next;
        //使temp的值写入到p位置的结点上
        fseek(fp1, -b2, 1);
        fwrite((char *)&temp, b2, 1, fp1);
        //使A[p]指向新插入的p结点
        A[d] = p;
    }
    //将数组A中的全部内容写回到索引文件的表头中
    fseek(fp1,0L,0);
    fseek(fp2,0L,0);
    fwrite((char *)A, b1 * (N+1), 1, fp2);
    free(A);
    fclose(fp1);
    fclose(fp2);

}
bool HashFileSearch(char *fname,struct Elemtype *x) //在散列文件中查找元素并返回查找结果
{
    struct FLNode temp;
    FILE *fp1, *fp2;
    fp1 = fopen(fname, "rb+");
    fp2 = fopen(Iname, "rb+");
    if(NULL == fp1|| NULL == fp2)
    {
        printf("打开文件失败!\n");
        exit(1);
    }
    int *A;
    A = (int *)calloc(N+1, b1);
    if(NULL == A)
    {
        printf("内存申请失败!\n");
        exit(1);
    }
    fread((char *)A, (N+1)*b1, 1, fp2);
    int d = x->key % N;
    int p = A[d];
    while(p != -1)
    {
        fseek(fp1, (N+1)*b1 + p*b2, 0);//在文件中定位
        fread((char *)&temp, b2, 1, fp1);
        if(temp.data.key == x->key)
        {
            *x = temp.data; //被查找到的元素由x带回
            break;
        }
        else
            p = temp.next;
    }
    free(A);
    fclose(fp1);
    fclose(fp2);
    if(-1 == p) return false;
    else return true;
}
void HashFileInsert(char filename[]) //向散列文件中插入一个元素
{
    struct Elemtype x;
    cout<<"请输入待插入元素的关键信息(序号):";
    cin>>x.key;
    cout<<endl;
    cout<<"请输入待插入元素的附加信息(字符):";
    cin>>x.rest;
    if(HashFileSearch(filename,&x)) cout<<"该元素在散列文件中已经存在,无需再次插入!"<<endl<<endl;
    else
    {
        cout<<"该元素在散列文件中不存在"<<endl<<endl;
        HashFileInOne(filename,x);
        cout<<"关键元素(序号)为"<<x.key<<"的元素经插入完成!"<<endl<<endl;
    }
}
void HashFilePrint(char *fname) //打印散列文件
{
    cout<<"散列文件如下:"<<endl;
    FILE *fp1, *fp2;
    fp1 = fopen(fname, "rb+");
    fp2 = fopen(Iname, "rb+");
    if(NULL == fp1|| NULL == fp2)
    {
        cout<<"文件打开失败"<<endl;
        exit(1);
    }
    int *A;
    A = (int *)calloc(N+1, b1);
    if(NULL == A)
    {
        cout<<"内存申请失败"<<endl;
        exit(1);
    }
    fread((char *)A, b1, N+1, fp2);
    int p;
    struct FLNode pn;
    for(int i = 0; i < N+1; i++)
    {
        printf("%d:", i);
        p = A[i];
        while(-1 != p)
        {
            fseek(fp1, (N+1)*b1 + p*b2, 0);  // 修改文件指针位置
            fread((char *)&pn, b2, 1, fp1);  // 从文件中中读取节点
            printf("%d->%d(%s)  ", p, pn.data.key, pn.data.rest);
            p = pn.next;
        }
        printf("\n");
    }
    free(A);
    fclose(fp1);
    fclose(fp2);
    cout<<"输出结束!"<<endl<<endl;
}
void InitHashFile(char *fname) //初始化散列文件
{
    cout<<"是否确认要初始化散列文件(0-退出 1-确认初始化):";
    bool choose;
    cin>>choose;
    cout<<endl;
    if(choose==0)
    {
        cout<<"****散列文件未进行初始化!"<<endl<<endl;
        return;
    }
    cout<<"****开始进行散列文件的初始化!"<<endl<<endl;
    FILE *fp1,*fp2;
    int *A;
    fp1 = fopen(fname, "wb+");
    fp2 = fopen(Iname, "wb+");
    if(NULL == fp1|| NULL == fp2)
    {
        printf("打开文件失败!/n");
        exit(1);
    }
    //动态分配具有N+1个整型储存空间的数组A
    A = (int *)calloc(N + 1, b1);
    if(NULL == A)
    {
        printf("内存申请失败!/n");
        exit(1);
    }

    //给数组A中的每个元素赋初值-1,表示空指针
    for(int i = 0; i < N + 1; i++)
    {
        A[i] = -1;
    }
    //初始化散列文件
    fwrite((char *)A, (N + 1)*b1, 1, fp1);
    fwrite((char *)A, (N + 1)*b1, 1, fp2);
    free(A);
    fclose(fp1);
    fclose(fp2);
    cout<<"****散列文件初始化已完成!"<<endl<<endl;
}
void existHash(char *fname) //检测是否存在散列文件
{
    FILE *fp1,*fp2;
    fp1 = fopen(fname, "rb");
    fp2 = fopen(Iname, "rb");
    if(fp1==NULL||fp2==NULL)
        cout<<"****系统中不存在散列文件,需要初始化散列文件后才可使用本系统****"<<endl<<endl;
    else
    {
        cout<<"****系统中已存在散列文件,可以直接使用****"<<endl<<endl;
        //只有存在散列文件的时候文件指针才有意义,才需要进行释放操作
        fclose(fp1);
        fclose(fp2);
    }

}
void welcome() //欢迎使用
{
    cout<<"               欢迎使用散列文件系统!"<<endl<<endl;
    existHash(filename);
}
int start() //模式选择函数
{
    int num;
    printf("\t+----------------------------------+\n");
    printf("\t|----------- 散列文件 -------------|\n");
    printf("\t|--1-- 初始化散列文件 -------------|\n");
    printf("\t|--2-- 向散列文件中插入一个元素 ---|\n");
    printf("\t|--3-- 从散列文件中删除一个元素 ---|\n");
    printf("\t|--4-- 从散列文件中查找一个元素 ---|\n");
    printf("\t|--5-- 打印散列文件 ---------------|\n");
    printf("\t|--0-- 结束运行 -------------------|\n");
    printf("\t+----------------------------------+\n");
    cout<<"****请输入您的选择(0-5):";
    cin>>num;
    cout<<endl;
    return num;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值