散列文件的插入、删除、查找和打印(C语言源代码)

来源:互联网 发布:php curl 选项 编辑:程序博客网 时间:2024/06/07 04:00
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <conio.h>
  5. /*定义散列表长度,其值取决于待三列的元素数量
  6. 和选取的装填因α的大小,在此假定为13*/
  7. #define N 13    
  8. /*定义关键字类型,这里假定为整型*/
  9. typedef int KeyType;
  10. struct ElemType     //元素类型
  11. {
  12.     KeyType key;    //关键字域
  13.     char rest[10];  //其他域,假定用字符数组表示
  14. };
  15. struct FLNode   //索引文件中的结点类型
  16. {
  17.     struct ElemType data;   //值域
  18.     int next;       //指向下一个结点的指针域
  19. };
  20. const int b1 = sizeof(KeyType); //用全局常量b1保存索引表文件中的记录(元素)长度
  21. const int b2 = sizeof(struct FLNode);   //用全局常量b2保存索引主文件中的记录(结点)长度
  22. //建立并初始化散列表文件
  23. void InitHashFile(char *fname)
  24. {
  25.     int i;
  26.     int *A;
  27.     //以读写方式新建二进制散列文件
  28.     FILE *fp;
  29.     fp = fopen(fname, "wb+");
  30.     if(NULL == fp)
  31.     {
  32.         printf("Cannot open this file!/n");
  33.         exit(1);
  34.     }
  35.     //动态分配具有N+1个整型储存空间的数组A
  36.     A = (int *)calloc(N + 1, b1);
  37.     if(NULL == A)
  38.     {
  39.         printf("Memory alloction failare!/n");
  40.         exit(1);
  41.     }
  42.     
  43.     //给数组A中的每个元素赋初值-1,表示空指针
  44.     for(i = 0; i < N + 1; i++)
  45.     {
  46.         A[i] = -1;
  47.     }
  48.     //初始化散列文件
  49.     fwrite((char *)A, (N + 1)*b1, 1, fp);
  50.     //删除数组A
  51.     free(A);
  52.     //关闭fp对应的文件
  53.     fclose(fp);
  54. }
  55. //检测是否存在散列文件
  56. void existHash(char *fname)
  57. {
  58.     char bcreate;
  59.     char filename[128];
  60.     FILE *fp;
  61.     fp = fopen(fname, "rb");
  62.     if(NULL == fp)
  63.     {
  64.         printf("--- 散列文件不存在, 是否新建散列文件(y:从新建立/n:打开其他散列文件)? ---/n");
  65.         scanf("%c", &bcreate);
  66.         if('y' == bcreate || 'Y' == bcreate)
  67.         {
  68.             InitHashFile(fname);
  69.             printf("--- 新建散列文件完毕! ---/n");
  70.         }
  71.         else
  72.         {
  73.             printf("请输入散列文件路径:/n");
  74.             scanf("%s", filename);
  75.             strcpy(fname, filename);
  76.             existHash(fname);
  77.         }
  78.     }
  79.     else
  80.     {
  81.         fclose(fp);
  82.     }
  83. }
  84. //把元素x插入到散列文件中
  85. void HFInsertOne(char *fname, struct ElemType x)
  86. {
  87.     int p;
  88.     int len;    //文件尾结点位置序号
  89.     int *A;
  90.     int d;
  91.     struct FLNode temp;
  92.     struct FLNode pn;
  93.     //以读写和不新建方式打开散列文件
  94.     FILE *fp;
  95.     fp = fopen(fname, "rb+");
  96.     if(NULL == fp)
  97.     {
  98.         printf("Cannot open this file!/n");
  99.         exit(1);
  100.     }
  101.     //动态分配具有N + 1个整型存储空间的数组
  102.     A = (int *)calloc(N + 1, b1);
  103.     if(!A)
  104.     {
  105.         printf("Memory alloction failare!/n");
  106.         exit(1);
  107.     }
  108.     //将散列文件的表头读入到数组A中
  109.     fread((char *)A, (N + 1) * b1, 1, fp);
  110.     //以关键字x.key计算x的散列地址,采用除留余数法
  111.     d = x.key % N;
  112.     //以x和A[d]的值构成待插入散列文件的内存节点temp   
  113.     temp.data = x;
  114.     temp.next = A[d];
  115.     //将temp结点的值写入到散列文件中,并链接到散列文件表头
  116.     //下表d单链表的表头
  117.     if(-1 == A[N])
  118.     {
  119.         //将文件指针移至文件尾
  120.         fseek(fp, 0L, 2);
  121.         //计算出文件尾的结点位置序号
  122.         len = (ftell(fp) - (N+1)*b1)/b2;
  123.         //将temp结点的值写入文件尾
  124.         fwrite((char *)&temp, b2, 1, fp);
  125.         //使A[d]指向新插入的结点
  126.         A[d] = len;
  127.     }
  128.     else
  129.     {
  130.         //p指向空闲单链表的表头结点
  131.         p = A[N];
  132.         //使空闲单链表的表头指针指向其下一个结点
  133.         fseek(fp, b1 * (N+1) + p*b2, 0);
  134.         fread((char *)&pn, b2, 1, fp);
  135.         A[N] = pn.next;
  136.         //使temp的值写入到p位置的结点上
  137.         fseek(fp, -b2, 1);
  138.         fwrite((char *)&temp, b2, 1, fp);
  139.         //使A[p]指向新插入的p结点
  140.         A[d] = p;
  141.     }
  142.     //将数组A中的全部内容写回到散列文件的表头中
  143.     fseek(fp,0L,0);
  144.     fwrite((char *)A, b1 * (N+1), 1, fp);
  145.     //删除动态数组A和关闭散列文件
  146.     free(A);
  147.     fclose(fp);
  148. }
  149. //从散列文件中删除关键字尾x.key的元素,并有x带回该
  150. //元素,若删除成功则返回1,否则返回0
  151. int HFDelete(char *fname, struct ElemType *x)
  152. {
  153.     struct FLNode tp,tq;
  154.     int p, q;
  155.     int *A;
  156.     int d;
  157.     FILE *fp;
  158.     //打开散列文件
  159.     fp = fopen(fname, "rb+");
  160.     if(NULL == fp)
  161.     {
  162.         printf("Cannot open this file!/n");
  163.         exit(1);
  164.     }
  165.     //申请动态数组A
  166.     A = (int *)calloc(N+1, b1);
  167.     if(NULL == A)
  168.     {
  169.         printf("Memory alloction failare!/n");
  170.         exit(1);
  171.     }
  172.     //将散列文件表头读入数组A中
  173.     fread((char *)A, (N+1)*b1, 1, fp);
  174.     
  175.     //计算散列地址d
  176.     d = x->key % N;
  177.     p= A[d];
  178.     while(-1 != p)
  179.     {
  180.         fseek(fp, (N+1)*b1+p*b2, 0);
  181.         fread((char*)&tp, b2, 1, fp);
  182.         if(tp.data.key  == x->key)
  183.         {
  184.             //被删除结点的元素值赋给x带回
  185.             *x = tp.data;
  186.             //从单链表中删除p结点
  187.             if(p == A[d])
  188.             {
  189.                 A[d] = tp.next;
  190.             }
  191.             else
  192.             {
  193.                 tq.next = tp.next;
  194.                 fseek(fp, (N+1)*b1+q*b2, 0);
  195.                 fwrite((char *)&tq, b2, 1, fp);
  196.             }
  197.             //将p结点连接到空闲单链表的表头
  198.             tp.next = A[N];
  199.             fseek(fp, (N+1)*b1+p*b2, 0);
  200.             fwrite((char *)&tp, b2, 1,fp);
  201.             A[N] = p;
  202.             //结束while循环
  203.             break;
  204.         }
  205.         else
  206.         {
  207.             //使p指针的值赋给q,tp结点的值赋值给tq结点
  208.             q = p;
  209.             tq = tp;
  210.             //p指向单链表中的下一个结点
  211.             p = tp.next;
  212.         }//if分支结束
  213.     }//while循环结束
  214.     //将文件指针移到文件头部,并将散列文件的表头重新写入散列文件
  215.     fseek(fp, 0L, 0);
  216.     fwrite((char *)A, (N + 1) * b1, 1, fp);
  217.     //释放A数组申请的内存空间
  218.     free(A);
  219.     //关闭散列文件
  220.     fclose(fp);
  221.     if(-1 == p)
  222.     {
  223.         return 0;   //没有找到要删除的结点
  224.     }   
  225.     else
  226.     {
  227.         return 1;   //成功删除要删除的结点
  228.     }//if分支结构结束
  229. }
  230. //从散列文件中查找关键字为x.key的元素,并由x带回
  231. //元素,若查找成功则返回1,否则返回0
  232. int HFSearch(char *fname, struct ElemType *x)
  233. {
  234.     int d;
  235.     int p;
  236.     int *A;
  237.     struct FLNode temp;
  238.     //以读写方式打开散列文件
  239.     FILE *fp;
  240.     fp = fopen(fname, "rb+");
  241.     if(NULL == fp)
  242.     {
  243.         printf("Cannot open this file!/n");
  244.         exit(1);
  245.     }
  246.     //申请动态数组A
  247.     A = (int *)calloc(N+1, b1);
  248.     if(NULL == A)
  249.     {
  250.         printf("Momery alloction failare!/n");
  251.         exit(1);
  252.     }
  253.     fread((char *)A, (N+1)*b1, 1, fp);
  254.     d = x->key % N;
  255.     //取出d单链表的表头指针
  256.     p = A[d];
  257.     //从d点链表中查找关键字为x.key的元素
  258.     while(p != -1)
  259.     {
  260.         fseek(fp, (N+1)*b1 + p*b2, 0);
  261.         fread((char *)&temp, b2, 1, fp);
  262.         if(temp.data.key == x->key)
  263.         {
  264.             *x = temp.data; //被查找到的元素由x带回
  265.             break;
  266.         }
  267.         else
  268.         {
  269.             p = temp.next;  //把结点指针移到下一个结点
  270.         }
  271.     }
  272.     //释放A数组申请的内存空间
  273.     free(A);
  274.     //关闭散列文件
  275.     fclose(fp);
  276.     if(-1 == p)
  277.     {
  278.         return 0;   
  279.     }   
  280.     else
  281.     {
  282.         return 1;   
  283.     }//if分支结构结束
  284. }
  285. //顺序打印出散列文件中的每个单链表中的每个结点位置序号及元素值
  286. void HFPrint(char *fname)
  287. {
  288.     int i;
  289.     int p;
  290.     int *A;
  291.     struct FLNode pn;
  292.     //以读写方式打开散列文件
  293.     FILE *fp;
  294.     fp = fopen(fname, "rb+");
  295.     if(NULL == fp)
  296.     {
  297.         printf("Cannot open this file!/n");
  298.         exit(1);
  299.     }
  300.     
  301.     //申请动态数组A
  302.     A = (int *)calloc(N+1, b1);
  303.     if(NULL == A)
  304.     {
  305.         printf("Momery alloction failare!/n");
  306.         exit(1);
  307.     }
  308.     fread((char *)A, (N+1)*b1, 1, fp);
  309.     for(i = 0; i < N+1; i++)
  310.     {
  311.         printf("%d:", i);
  312.         p = A[i];
  313.         while(-1 != p)
  314.         {
  315.             fseek(fp, (N+1)*b1 + p*b2, 0);
  316.             fread((char *)&pn, b2, 1, fp);
  317.             printf("%d->%d  ", p, pn.data.key);
  318.             p = pn.next;
  319.         }
  320.         printf("/n");
  321.     }
  322.     
  323.     //删除动态数组A申请的内存
  324.     free(A);
  325.     //关闭散列文件
  326.     fclose(fp);
  327. }
  328. //main函数
  329. void main()
  330. {
  331.     struct ElemType x;
  332.     int number; //选择的功能号表
  333.     char ch;
  334.     //定义tag用于保存或查找函数的返回值
  335.     int tag;
  336.     //定义散列文件的名字,为字符指针filename指向的字符串
  337.     char filename[128];
  338.     strcpy(filename, "Hash");
  339.     //检测散列文件是否存在
  340.     existHash(filename);
  341.     while(1)
  342.     {
  343.         printf("/n");
  344.         printf("/03-----------------------------------/03/n");
  345.         printf("/03------------ 散列文件 -------------/03/n");
  346.         printf("/03 1---- 初始化散列文件 -------------/03/n");
  347.         printf("/03 2---- 向散列文件中插入一个元素 ---/03/n");
  348.         printf("/03 3---- 从散列文件中删除一个元素 ---/03/n");
  349.         printf("/03 4---- 从散列文件中查找一个元素 ---/03/n");
  350.         printf("/03 5---- 打印散列文件 ---------------/03/n");
  351.         printf("/03 0---- 结束运行 -------------------/03/n");
  352.         
  353.         printf("/03 请输入你的选择(1-5):");
  354.         scanf("%d", &number);
  355.         switch(number)
  356.         {
  357.             case 0:
  358.                 return;
  359.             case 1:
  360.                 //初始化散列文件
  361.                 printf("确实要重新初始化散列文件(y/n)?");
  362.                 getchar();
  363.                 scanf("%c", &ch);
  364.                 if('y' == ch || 'Y' == ch)
  365.                 {
  366.                     //重新初始化散列文件
  367.                     InitHashFile(filename); 
  368.                     printf("--- 重新初始化散列文件完毕! ---/n");
  369.                 }
  370.                 else
  371.                 {
  372.                     printf("--- 未执行重建散列文件操作! ---/n");
  373.                 }
  374.                 break;
  375.             case 2:
  376.                 //向散列文件中插入一个元素
  377.                 printf("输入待插入元素x的值(一个整数和一个字符串(长度小于10)):/n");
  378.                 scanf("%d", &x.key);
  379.                 scanf("%s", &x.rest);
  380.                 HFInsertOne(filename, x);
  381.                 break;
  382.             case 3:
  383.                 //从散列文件中删除一个元素
  384.                 printf("输入待删除元素x的关键字:");
  385.                 scanf("%d", &x.key);
  386.                 tag = HFDelete(filename, &x);
  387.                 if(1 == tag)
  388.                 {
  389.                     printf("--- 删除成功!%d %s ---/n", x.key, x.rest);
  390.                 }
  391.                 else
  392.                 {
  393.                     printf("--- 删除失败 ---/n");
  394.                 }   //if分支结构结束
  395.                 break;
  396.             case 4:
  397.                 //从散列文件中查找一个元素
  398.                 printf("输入待查找元素x的关键字:/n");
  399.                 scanf("%d", &x.key);
  400.                 tag = HFSearch(filename, &x);
  401.                 if(1 == tag)
  402.                 {
  403.                     printf("--- 查找成功!%d %s ---/n", x.key, x.rest);
  404.                 }
  405.                 else
  406.                 {
  407.                     printf("查找失败!/n");
  408.                 }
  409.                 break;
  410.             case 5:
  411.                 //打印散列文件
  412.                 HFPrint(filename);
  413.                 break;
  414.             default:
  415.                 printf("/n--- 输入功能号表错误 ---/n");
  416.                 break;
  417.         }   //switch结束
  418.         printf("--- 按任意键继续 ---/n");
  419.         getch();    //接收任意字符
  420.     }
  421. }
原创粉丝点击