散列的开放定址法中的平方探测法

平方探测是消除线性探测中聚集问题的冲突解决办法。平方探测就是冲突函数为二次函数的探测方法。流行的选择函数是F(i)=i²,例如插入89,18,49,58,69可以由下图看出,

  空表 插入89 插入18 插入49 插入58 插入69
0       49 49 49
1            
2         58 58
3           69
4            
5            
6            
7            
8     18 18 18 18
9   89 89 89 89 89

而对于平方探测法来说,一旦表被填满超过一半,当表的大小不是素数时甚至在表被填满一半之前,就不能保证一次找到一个空单元。而对于平方探测法来讲,其和线性探测法一样,san'删除的操作只能用懒惰删除。下面为其代码:

fatal.h

#include <stdio.h>
#include <stdlib.h>

#define Error(Str) FatalError(Str)
#define FatalError(Str) fprintf(stderr, "%s\n", Str), exit(1)

 hashquad.h

typedef char* ElementType;
 
#ifndef _Hashquad_H
#define _Hashquad_H
 
typedef unsigned int Index;
typedef Index Position;
 
struct HashTbl;
typedef struct HashTbl* HashTable;
 
HashTable initializeTable(int tableSize);
void destroyTable(HashTable h);
Position find(ElementType key, HashTable h);
HashTable insert(ElementType key, HashTable h);
HashTable rehash(HashTable h);
ElementType retrive(Position p,HashTable h);
#endif

 hashquad.cpp

#include"hashquad.h"
#include"fatal.h"
#include<math.h>
#include<string.h>
#define MinTableSize 5
#define N 10000
int ranintArr[N];
 
enum KindOfEntry { Legitimate, Empty, Deleted };
 
struct HashEntry 
{
	ElementType element;
	enum KindOfEntry info;
};
 
typedef struct HashEntry Cell;
 
struct HashTbl 
{
	int tableSize;//表的大小
    int num;//判断插入元素的个数
	Cell *theCells;//构建散列表项的单元数组
};
 

static int hash(ElementType key, int tableSize) 
{
	return key % (tableSize);
}


static int isPrime(int num) //判断素数
{
	for (int i = 2; i <= sqrt(num); i++)
    {
		if (num%i == 0)
        {
			return 0;
        }
    }
	return 1;
}


static int nextPrime(int num)//寻找素数作为表的大小 
{
	int i = num;
	while (!isPrime(i))
    {
		i++;
    }
	return i;
}
 

HashTable initializeTable(int tableSize)//散列表的初始化
 {
	HashTable h;
	int i;
	if (tableSize < MinTableSize) 
    {
		Error("Table size too small");
		return NULL;
	}

	h = malloc(sizeof(struct HashTbl));

	if (h == NULL)
    {  
		FatalError("Out of space!!!");
    }

	h->tableSize = nextPrime(tableSize);
	h->theCells = malloc(sizeof(Cell)*h->tableSize);
	h->hasInsertedNum = 0;

	if (h->theCells == NULL)
    {
		FatalError("Out of space!!!");
    }
	for (i = 0; i < h->tableSize; i++)
    {
		h->theCells[i].info = Empty;
	}
	return h;
}
 
void destroyTable(HashTable h) //删除散列表
{
	free(h->theCells);
	free(h);
}
 
Position find(ElementType key, HashTable h)//查找表中的元素 
{
	Position currentPos = hash(key, h->tableSize);
	int collisionNum = 0;
	while (h->theCells[currentPos].info != Empty && h->theCells[currentPos].element!= key) 
    {
		++collisionNum;
		currentPos = (currentPos +collisionNum*2-1) % h->tableSize;
	}
	return currentPos;
}
 
HashTable insert(ElementType key, HashTable h)//插入 
{
	if ((double)h->num / h->tableSize > 0.5)
    {
		h = rehash(h);
    }

	Position pos = find(key, h);

	if (h->theCells[pos].info != Legitimate) 
    {
		h->theCells[pos].element=key;
		h->theCells[pos].info = Legitimate;
		h->num++;
	}
	return h;
}
 
HashTable rehash(HashTable h)
{
    int i;
	HashTable newH = initializeTable(h->tableSize * 2);

	for (i = 0; i < h->tableSize; i++)
    {
		if (h->theCells[i].info == Legitimate)
        {
			insert(h->theCells[i].element, newH);
        }
    }

	destroyTable(h);
	return newH;
}
 
 
ElementType retrive(Position p, HashTable h) 
{
	return h->theCells[p].element;
}


int RandInt(int i, int j) 
{
	int temp;
	temp = (int)(i + (1.0*rand() / RAND_MAX)*(j - i));
	return temp;
}
 

void getRandomInt(int *A, int n) 
{
	for (int i = 0; i < n; ++i) 
    {
		A[i] = i + 1;
	}
 
	for (int i = 1; i < n; ++i) //std::swap(A[i], A[RandInt(0, i)]);
    {   
		int randAdrr = RandInt(0, i);
		int t = A[i];
		A[i] = A[randAdrr];
		A[randAdrr] = t;
	}
}
 
 

main.cpp

#include<stdlib.h>
#include"hashquad.h"
#include<stdio.h>
 
int main() 
{
	getRandomInt(ranintArr, N);
	
	HashTable h = initializeTable(10);
	for (int i = 0; i < N; i++)
    {
		h = insert(ranintArr[i], h);
	}
	
	Position p = find(100, h);
	if (isLegitimate(p, h))
    {
		printf("%d", retrive(p, h));
    }
 
	destroyTable(h);

    return 0;
}

但是平方探测法只能消除一次的聚集问题,而对于二次聚集,那就得用到双散列了。 

猜你喜欢

转载自blog.csdn.net/u012178728/article/details/81124999
今日推荐