zoukankan      html  css  js  c++  java
  • 散列查找-平方探测法

    • 解决散列表的冲突问题有两种办法:开放地址法和链地址法

    下面的代码是采用开放地址法,平方探测时的代码。

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <stdbool.h>
    
    #define MAXTABLESIZE 100
    
    typedef int ElementType;
    
    //散列单元状态类型
    typedef enum
    {
        Legitimate,  //有合法元素
    	Empty, //空单元
    	Deleted  //有已删除元素
    }EntryType;
    
    struct HashEntry  //散列表的单元类型
    {
    	ElementType Data;  //存放元素
    	EntryType Info;  //单元状态
    };
    
    struct TblNode  //散列表的节点定义
    {
    	int TableSize;  //表的最大长度
    	struct HashEntry* Cells;  //存放散列单元数据的数组
    };
    
    //返回大于N且不超过MAXTABLESIZE的素数
    int NextPrime(int N)
    {
    	int i;
    	int p = (N % 2) ? N + 2 : N + 1;  //从大于N的下一个奇数开始
    
    	while (p <= MAXTABLESIZE)
    	{
    		for (i = (int)sqrt(p); i > 2; i--)
    		{
    			if (!(p % i))
    			{
    				break;  //p不是素数
    			}
    		}
    		if (i == 2)
    		{
    			break;
    		}
    		else
    		{
    			p = p + 2;
    		}
    		
    	}
    
    	return p;
    }
    
    struct TblNode* CreateTable(int TableSize)
    {
    	struct TblNode* Hash;
    	int i;
    
    	Hash = (struct TblNode*)malloc(sizeof(struct TblNode));
    	Hash->TableSize = NextPrime(TableSize);  //保证散列表的最大长度是一个素数
    	//声明单元组
    	Hash->Cells = (struct HashEntry*)malloc(Hash->TableSize * sizeof(struct HashEntry));
    	//初始化单元状态为空单元
    	for (int i = 0;i < Hash->TableSize;i++)
    	{
    		Hash->Cells[i].Info = Empty;
    	}
    
    	return Hash;
    }
    
    int GetHashPos(ElementType Key,int TableSize)
    {
    	return Key % 11;
    }
    //
    int Find(struct TblNode* Hash,ElementType Key)
    {
    	int CurrentPos;
    	int NewPos;
    	int CNum = 0;  //记录冲突次数
    
    	NewPos = CurrentPos = GetHashPos(Key,Hash->TableSize);  //初始散列位置
    
    	while (Hash->Cells[NewPos].Info != Empty &&
    		   Hash->Cells[NewPos].Data != Key)
    	{
    		//统计1次冲突 并判断奇偶次
    		if (++CNum % 2)  //奇数次冲突
    		{
    			//增量为 +[(CNum+1)/2]^2
    			NewPos = CurrentPos + (CNum + 1) * (CNum + 1) / 4;
    			if (NewPos >= Hash->TableSize)
    			{
    				NewPos = NewPos % Hash->TableSize;  //调整为合法地址
    			}
    		}
    		else  //偶数次冲突
    		{ 
    			NewPos = CurrentPos - CNum * CNum / 4;
    			while (NewPos < 0)
    			{
    				NewPos = NewPos + Hash->TableSize;  //调整为合法地址
    			}
    		}
    	}
    	//此时NewPos或者是Key的位置,或者是一个空单元的位置(表示找不到)
    	return NewPos;
    }
    //将元素插入哈希表
    bool Insert(struct TblNode* Hash,ElementType Key)
    {
    	int  pos = Find(Hash,Key);
    
    	if (Hash->Cells[pos].Info != Legitimate)
    	{
    		//如果这个单元格没有被占,说明key可以插入在此
    		Hash->Cells[pos].Data = Key;
    		Hash->Cells[pos].Info = Legitimate;
    		return true;
    	}
    	else
    	{
    		printf("键值已存在.
    ");
    		return false;
    	}
    
    }
    
    int main()
    {
    	int a[] = {47,7,29,11,9,84,54,20,30};
    	//这里传入的值是9,但创建的HashTable的size并不是9,而是11
    	struct TblNode* HashTable = CreateTable(9);
    
    	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    	{
    		if (!Insert(HashTable, a[i]))
    		{
    			printf("插入元素失败.
    ");
    		}
    	}
    	printf("插入元素成功.
    ");
    	//访问元素
    	for (int i = 0; i < HashTable->TableSize; i++)
    	{
    		if (HashTable->Cells[i].Info == Legitimate)
    		{
    			printf("%d  %d.
    ", i, HashTable->Cells[i].Data);
    		}
    	}
    	system("pause");
    	return 0;
    }
    
    
    • 运行结果

    • 参考资料
      1 《数据结构(第2版)》 陈越主编 高等教育出版社
  • 相关阅读:
    说说委托是个什么东西,以及委托有什么用
    Fedora/Centos使用dnf/yum为Firefox安装Flash,两行命令超简单
    Debian中的NVIDIA显卡驱动安装——超简单,一行命令
    对象、字段、属性、方法、成员、接口各自含义
    C#中的字段与属性的区别及属性的作用
    C#的foreach遍历循环和隐式类型变量
    依赖注入的通俗讲解,设计低耦合的系统
    群晖moments提示错误代码117的解决方案
    群晖数据库错误解决
    解决终端录制工具asciinema 的错误
  • 原文地址:https://www.cnblogs.com/Manual-Linux/p/11404654.html
Copyright © 2011-2022 走看看