Chinaunix首页 | 论坛 | 博客
  • 博客访问: 153194
  • 博文数量: 36
  • 博客积分: 802
  • 博客等级: 准尉
  • 技术积分: 717
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-02 22:47
文章分类
文章存档

2012年(36)

分类: C/C++

2012-09-10 10:41:17

散列表:理想的散列表数据结构不过是一个包含有关键字的具有固定大小的数组,我们把表的大小记做TableSize,并将其理解为散列数据结构的一部分而不仅仅是浮动于全局的某个变量。
散列函数:每个关键字被映射到0~Tablesize这个范围中的某个数,并且被放在适当的单元中,这个映射就叫做散列函数。

------我们必须选择一个函数,决定当两个关键字散列到同一个值的时候,应该如何处理。

处理这种冲突最简单的两种方法:分离链接法和开放定址法

一:分离链接法
做法是将散列到同一个值的所有元素保存到一个表中。
首先我们得定义:

  

点击(此处)折叠或打

  1. typedef struct LinkNode
  2.   {
  3.    int elem;
  4.    struct LinkNode *next
  5.   }*List;// 这个结构体记录了取这个值的所有数所在的链表

  6. typedef struct HashTbl
  7.  {
  8.    int Tablesize;
  9.    List *TheList;//指针的指针,指向每一个值的链表
  10.  }*HashTable;
然后我们实现这个表的初始化函数

点击(此处)折叠或打开

  1. HashTable Init(int Size)
  2.   {
  3.   HashTable H;
  4.   int i;
  5.   if(Tablesize<MinSize)
  6.   {
  7.    perror("Out of space!\n");
  8.    return NULL;
  9.    }
  10.   H=(HashTable)malloc(sizeof(struct HashTbl));
  11.   if(H==NULL)
  12.   perror("Out of space!\n");
  13.   H->Tablesize=Size;
  14.   H->TheList=(List)malloc(sizeof(struct LinkNode)*Size);
  15.   if(H->TheList==NULL)
  16.      perror("Out of space!\n");
  17.   for(i=0;i<H->Tablesize;i++)
  18.   {
  19.      H->TheList[i]=(List)malloc(sizeof(LinkNOde));
  20.      if(H->TheList=[i]==NULL)
  21.           perror("Out of space!\n");
  22.      else
  23.           H->TheList[i]->next=NULL;
  24.   }
  25.   return H;
  26.   }
这个是寻找key这个元素位置的一个函数,返回值是行

点击(此处)折叠或打开

  1. struct ListNode Find(int key,HashTable H)
  2.     {
  3.     struct Node *p;
  4.     List L;
  5.     L=H->TheList(Hash(key,H->Tablesize));
  6.     p=L->next;
  7.     while(p!=NULL&&p->elem!=key)
  8.     p=p->next;
  9.     return p;
  10. }
接着是我门的插入函数

点击(此处)折叠或打开

  1. void Insert(int key,HashTable H)
  2.    {
  3.     List Pos,NewCell;
  4.    List L;
  5.    Pos=Find(key,H);
  6.    if(Pos==NULL)
  7.   {
  8.    NewCell=malloc(sizeof(struct ListNode));
  9.    if(NewCell==NULL)
  10.   perror("Out of space!\n");
  11.   else
  12.   {
  13.    NewCell->elem=key;
  14.   L=H->TheList(Hash(key,H->Tablesize));
  15.    NewCell->next=L->next;
  16.    L->next=NewCell;
  17.    }
  18.   }
  19.   }
我们给出分离链接法的全部代码


点击(此处)折叠或打开

  1. 1. #include<stdio.h>
  2.    2. #include<stdlib.h>
  3.    3.

  4.    4. #define MinTablesize 10
  5.    5. #define Size 15
  6.    6.

  7.    7. typedef struct ListNode
  8.    8. {
  9.    9. int elem;
  10.   10. struct ListNode *next;
  11.   11. }*List;
  12.   12.

  13.   13. typedef struct HashTbl
  14.   14. {
  15.   15. int Tablesize;
  16.   16. List *TheList;
  17.   17. }*HashTable;
  18.   18. HashTable InitializeTable(int Tablesize)
  19.   19. {
  20.   20. HashTable H;
  21.   21. int i;
  22.   22. if(Tablesize<MinTablesize)
  23.   23. {
  24.   24. perror("ERROR!\n");
  25.   25. return NULL;
  26.   26. }
  27.   27.

  28.   28. H=(HashTable)malloc(sizeof(struct HashTbl));
  29.   29. if(H==NULL)
  30.   30. perror("Out of space!\n");
  31.   31. H->Tablesize=Size;
  32.   32.

  33.   33. H->TheList=malloc(H->Tablesize*sizeof(struct ListNode));
  34.   34. if(H->TheList==NULL)
  35.   35. perror("Out of space!\n");
  36.   36.

  37.   37. for(i=0;i<H->Tablesize;i++)
  38.   38. {
  39.   39. H->TheList[i]=malloc(sizeof(struct ListNode));
  40.   40. if(H->TheList[i]==NULL)
  41.   41. perror("Out of space!\n");
  42.   42. else
  43.   43. H->TheList[i]->next=NULL;
  44.   44. }
  45.   45. return H;
  46.   46. }
  47.   47.

  48.   48. int Hash(int key,int x)
  49.   49. {
  50.   50. int i;
  51.   51. i=key%x;
  52.   52. return i;
  53.   53. }
  54.   54. struct ListNode *Find(int key,HashTable H)
  55.   55. {
  56.   56. struct ListNode *P;
  57.   57. List L;
  58.   58.

  59.   59. L=H->TheList[Hash(key,H->Tablesize)];
  60.   60. P=L->next;
  61.   61. while(P!=NULL&&P->elem!=key)
  62.   62. P=P->next;
  63.   63. return P;
  64.   64. }
  65.   65. void Insert(int key,HashTable H)
  66.   66. {
  67.   67. struct ListNode *Pos,*NewCell;
  68.   68. List L;
  69.   69. Pos=Find(key,H);
  70.   70. if(Pos==NULL)
  71.   71. {
  72.   72. NewCell=(List)malloc(sizeof(struct ListNode));
  73.   73. if(NewCell==NULL)
  74.   74. perror("Out of space!!!\n");
  75.   75. else
  76.   76. {
  77.   77. NewCell->elem=key;
  78.   78. L=H->TheList[Hash(key,H->Tablesize)];
  79.   79. NewCell->next=L->next;
  80.   80. L->next=NewCell;
  81.   81. }
  82.   82. }
  83.   83.

  84.   84. }
  85.   85.

  86.   86. void Print(HashTable H)
  87.   87. {
  88.   88. int i;
  89.   89. struct ListNode *p;
  90.   90. for(i=0;i<15;i++)
  91.   91. { printf("第%d组的成员有:\n",i);
  92.   92. p=H->TheList[i]->next;
  93.   93. while(p)
  94.   94. {
  95.   95. printf("%d ",p->elem);
  96.   96. p=p->next;
  97.   97. }
  98.   98. printf("\n");
  99.   99. }
  100.  100.

  101.  101. }
  102.  102. int main()
  103.  103. {
  104.  104. HashTable H;
  105.  105. int i;
  106.  106. int key;
  107.  107. int a[15];
  108.  108. List t,p;
  109.  109. H=InitializeTable(Size);
  110.  110. printf("please input number into Hash:");
  111.  111. for(i=0;i<15;i++)
  112.  112. scanf("%d",&a[i]);
  113.  113. for(i=0;i<Size;i++)
  114.  114. Insert(a[i],H);
  115.  115. Print(H);
  116.  116. key=2;
  117.  117. printf("please find %d\n",key);
  118.  118. t=Find(key,H);
  119.  119. if(t->elem==key)
  120.  120. printf("I can find %d\n",t->elem);
  121.  121. else
  122.  122. printf("I can not find the key!!!\n");
  123.  123.
  124.  124.

  125.  125. }
二:开放定址法
1:线性探测法
这个方法就是如果要插入的位置被占用,则往后退一个位置,直到找到位置可插入为止
2:平方探测法
这个方法就是分别取1平方,2平方,依次往下
下面给出这个方法的全部代码

 

点击(此处)折叠或打开

  1. 1. #include<stdio.h>
  2.    2. #include<stdlib.h>
  3.    3.

  4.    4. #define Size 50
  5.    5. #define MinSize 9
  6.    6.

  7.    7. enum KindofEntry
  8.    8. {
  9.    9. Legitimate,Empty,Deleted
  10.   10. };
  11.   11. struct HashEntry
  12.   12. {
  13.   13. int elem;
  14.   14. enum KindofEntry Info;
  15.   15. };
  16.   16.

  17.   17. typedef struct HashEntry Cell;
  18.   18.

  19.   19. struct HashTbl
  20.   20. {
  21.   21. int Tablesize;
  22.   22. Cell *Thecells;
  23.   23. };
  24.   24.

  25.   25. typedef struct HashTbl *HashTable;
  26.   26.

  27.   27. HashTable InitializeTable(int Tablesize)
  28.   28. {
  29.   29. HashTable H;
  30.   30. int i;
  31.   31. if(Size<MinSize)
  32.   32. {
  33.   33. perror("Table size too small!\n");
  34.   34. return NULL;
  35.   35. }
  36.   36. H=(HashTable)malloc(sizeof(struct HashTbl));
  37.   37. if(H==NULL)
  38.   38. printf("Out of space!\n");
  39.   39. H->Tablesize=Size;
  40.   40. H->Thecells=(Cell *)malloc(sizeof(Cell)*H->Tablesize);
  41.   41. if(H->Thecells==NULL)
  42.   42. perror("Out of space!\n");
  43.   43. for(i=0;i<Size;i++)
  44.   44. {
  45.   45. H->Thecells[i].Info=Empty;
  46.   46. H->Thecells[i].elem=0;
  47.   47. }
  48.   48. return H;
  49.   49. }
  50.   50. int Hash(int key,int x)
  51.   51. {
  52.   52. int i;
  53.   53. i=key%x;
  54.   54. return i;
  55.   55. }
  56.   56.

  57.   57. unsigned int Find(int key,HashTable H)
  58.   58. {
  59.   59. unsigned int Pos;
  60.   60. int Num;
  61.   61. Num=0;
  62.   62. Pos=Hash(key,H->Tablesize);
  63.   63. while((H->Thecells[Pos].Info!=Empty)&&(H->Thecells[Pos].elem!=key))
  64.   64. {
  65.   65. Pos+=2*++Num-1;
  66.   66. if(Pos>H->Tablesize)
  67.   67. Pos-=Size;
  68.   68. }
  69.   69. return Pos;
  70.   70. }
  71.   71.

  72.   72. void Insert(int key,HashTable H)
  73.   73. {
  74.   74. unsigned Pos;
  75.   75. Pos=Find(key,H);
  76.   76. if(H->Thecells[Pos].Info!=Legitimate)
  77.   77. {
  78.   78. H->Thecells[Pos].Info=Legitimate;
  79.   79. H->Thecells[Pos].elem=key;
  80.   80. }
  81.   81. }
  82.   82.

  83.   83. void Print(HashTable H,int data[])
  84.   84. {
  85.   85. int b=0;
  86.   86. unsigned int m;
  87.   87. for(b=0;b<15;b++)
  88.   88. {
  89.   89. m=Find(data[b],H);
  90.   90. printf("%d在第%d行\n",data[b],m);
  91.   91. }
  92.   92. }
  93.   93.

  94.   94. int main()
  95.   95. {
  96.   96. int i;
  97.   97. int data[15];
  98.   98. HashTable H;
  99.   99. H=InitializeTable(Size);
  100.  100. printf("请输入要插入哈西表的元素:\n");
  101.  101. for(i=0;i<15;i++)
  102.  102. scanf("%d",&data[i]);
  103.  103. printf("插入之后的哈西表为:\n");
  104.  104. for(i=0;i<15;i++)
  105.  105. Insert(data[i],H);
  106.  106. Print(H,data);
  107.  107.

  108.  108. }
三:再散列法
这个方法是当表填写过于满的时候,我们重新建立一个表。
eg:将13,15,24,6插入一个大小为7的开放定址散列表中,如果再插入23,则这个表就会有超过%70的空间被填满,所以我们再创建一个新表,新表的大小为17(因为2*7是14,而17是大于7的二倍之后第一个素数),然后再进行插入操作
这个再散列方法比较简单:
再散列可以永平方探测以多种方式实现:
1)只要表填满一半就开是再散列
2)只有当插入失败再散列
3)当表达到一定的装填因子的时候再散列

点击(此处)折叠或打开

  1. HashTable Rehash(HashTable H)
  2.    {
  3.    int i,oldsize;
  4.    Cell *OldCells;

  5.    oldsize=H->Tablesize;
  6.    OldCells=H->TheCells;

  7.    H=InitializeTable(2*oldsize)

  8.    for(i=0;i<oldsize;i++)
  9.   if(OldCell[i].Info==Legitimate)
  10.   Insert(OldCells[i].elem,H);
  11.   free(OldCells);
  12.    return H;
  13.   }

阅读(1677) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~