key:可以判断一个单词是否拼写错误,判断网名是否存在等等;
key value:实现中英文字典,统计单词出现次数等等;key value 需要在结构体中在存一个值value(中文、出现次数)
代码如下:
BinarySearchTree.h
#pragma once
//利用二叉搜索树 key value:中英文翻译
typedef char* BSTKeyType;
typedef char* BSTValueType;//翻译
//typedef int BSTValueType;//统计次数
typedef struct BSTreeNode
{
struct BSTreeNode *left;
struct BSTreeNode *right;
BSTKeyType _key;
BSTValueType _value;
}BSTreeNode;
int BSTreeInsert(BSTreeNode **pptree, BSTKeyType x, BSTValueType value);//插入数据
BSTreeNode *BuyBSTreeNode(BSTKeyType x, BSTValueType value);//创建结点
void BSTreeInOrder(BSTreeNode *ptree);//中序遍历
const BSTreeNode *FindBSTreeNode(BSTreeNode *ptree, BSTKeyType key);//查找元素
int BSTreeNodeRemove(BSTreeNode **pptree, BSTKeyType x);//删除
int BSTreeInsertR(BSTreeNode **pptree, BSTKeyType x, BSTValueType value);//递归插入
BSTreeNode* BSTreeFindNodeR(BSTreeNode *pptree, BSTKeyType key);//递归查找
int BSTreeRemoveR(BSTreeNode **pptree, BSTKeyType key);//递归删除
BinarySearchTree.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"BinarySearchTree.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
BSTreeNode *BuyBSTreeNode(BSTKeyType key, BSTValueType value)//创建结点
{
BSTreeNode *newnode = (BSTreeNode *)malloc(sizeof(BSTreeNode));
if (newnode == NULL)
return NULL;
else
{
newnode->_key = key;
newnode->_value = value;
newnode->left = NULL;
newnode->right = NULL;
return newnode;
}
}
int BSTreeInsert(BSTreeNode **pptree, BSTKeyType key, BSTValueType value)//插入数据
{
BSTreeNode *node = BuyBSTreeNode(key,value);
BSTreeNode *parent = NULL, *cur = *pptree;
if (*pptree == NULL)
{
*pptree = node;
return 0;
}
while (cur)
{
if (strcmp(cur->_key, key)< 0)
{
parent = cur;
cur = cur->right;
}
else if (strcmp(cur->_key, key) > 0)
{
parent = cur;
cur = cur->left;
}
else
return -1;//插入元素已经存在,则不进行插入
}
if (parent->_key > key)
parent->left = node;
else
parent->right = node;
return 0;
}
void BSTreeInOrder(BSTreeNode *ptree)//中序遍历
{
if (ptree == NULL)
return;
BSTreeInOrder(ptree->left);
printf("%s:%s ", ptree->_key,ptree->_value);
BSTreeInOrder(ptree->right);
}
const BSTreeNode *FindBSTreeNode(BSTreeNode *ptree, BSTKeyType key)//查找元素
{
assert(ptree);
BSTreeNode *cur = ptree;
while (cur)
{
if (strcmp(cur->_key, key) < 0)
cur = cur->right;
else if (strcmp(cur->_key, key)> 0)
cur = cur->left;
else
return cur;
}
return NULL;
}
int BSTreeNodeRemove(BSTreeNode **pptree, BSTKeyType key)//删除
{
assert(*pptree);
BSTreeNode *cur = *pptree, *parent = *pptree;
while (cur)//找到删除结点
{
if (strcmp(cur->_key, key)< 0)
{
parent = cur;
cur = cur->right;
}
else if (strcmp(cur->_key, key)> 0)
{
parent = cur;
cur = cur->left;
}
else
break;
}
if (cur->left == NULL)//左为空
{
if (strcmp(parent->_key, key) < 0)
parent->right = cur->right;
else if (strcmp(parent->_key, key)> 0)
parent->left = cur->right;
else
{
BSTreeNode *subleft, *parentnode = cur;
subleft = cur->right;
if (subleft)
{
while (subleft->left)
{
parentnode = subleft;
subleft = subleft->left;
}
cur->_key= subleft->_key;
if (parentnode->right == subleft)
parentnode->right = subleft->right;
else
parentnode->left = subleft->right;
free(subleft);
subleft = NULL;
}
else
{ //说明*pptree是根结点,而且只有这一个根结点
*pptree = NULL;
}
}
return 0;
}
if (cur->right == NULL)//右为空
{
if (strcmp(parent->_key, key) < 0)
parent->right = cur->left;
else if (strcmp(parent->_key, key)> 0)
parent->left = cur->left;
else
{
//说明删除根结点
BSTreeNode *subright, *parentnode = cur;
subright = cur->left;
if (subright)
{
while (subright->right)
{
parentnode = subright;
subright = subright->right;
}
cur->_key= subright->_key;
if (parentnode->left == subright)
parentnode->left = subright->left;
else
parentnode->right = subright->left;
free(subright);
subright = NULL;
}
}
return 0;
}
BSTreeNode *subleft, *parentnode = cur;
subleft = cur->right;
while (subleft->left)
{
parentnode = subleft;
subleft = subleft->left;
}
cur->_key = subleft->_key;
if (parentnode->left == subleft)
parentnode->left = subleft->right;
else
parentnode->right = subleft->right;
free(subleft);
return 0;
}
int BSTreeInsertR(BSTreeNode **pptree, BSTKeyType key, BSTValueType value)//递归插入
{
BSTreeNode *newnode = BuyBSTreeNode(key,value);
if (*pptree == NULL)
{ //由于pptree是二级指针,解引用后就是上一个pptree->left或pptree->right
//具有天然的将父亲与孩子链接起来
*pptree = newnode;
return 0;
}
if (strcmp((*pptree)->_key ,key)<0)
{
return BSTreeInsertR(&(*pptree)->right, key,value);
}
else if (strcmp((*pptree)->_key, key)>0)
{
return BSTreeInsertR(&(*pptree)->left, key,value);
}
else
return -1;
}
BSTreeNode * BSTreeFindNodeR(BSTreeNode *pptree, BSTKeyType key)//递归查找
{
if (pptree == NULL)
return NULL;
if (strcmp(pptree->_key, key)==0)//用字符串内容进行比较
return pptree;
else if (strcmp(pptree->_key, key) < 0)
return BSTreeFindNodeR(pptree->right, key);
else
return BSTreeFindNodeR(pptree->left, key);
}
int BSTreeRemoveR(BSTreeNode **pptree, BSTKeyType key)//递归删除
{
if (*pptree == NULL)//是空证明没有该结点,直接返回
return -1;
if (strcmp((*pptree)->_key, key)<0)//在右子树里删除
return BSTreeRemoveR(&(*pptree)->right, key);//递归删除
else if (strcmp((*pptree)->_key, key)>0)//在左子树里删除
return BSTreeRemoveR(&(*pptree)->left, key);
else
{
BSTreeNode *del = *pptree;
//叶子结点可以涵盖在左为空或者右为空中
if ((*pptree)->left == NULL)//左为空
{
*pptree = (*pptree)->right;
free(del);
return 0;
}
else if ((*pptree)->right == NULL)//右为空
{
*pptree = (*pptree)->left;//利用二级指针解引用
free(del);
return 0;
}
else
{
BSTreeNode *subleft = (*pptree)->right;
while (subleft->left)
subleft = subleft->left;
(*pptree)->_key = subleft->_key;
//然后把subleft删除,参数里不能写成(subleft,subleft->_key),
//因为subleft是局部变量
return BSTreeRemoveR(&(*pptree)->right, subleft->_key);//递归删除
}
}
}
//void TestBinarySearch()
//{
// //用字符串地址进行比较,行不通
// BSTreeNode *tree = NULL;
// char *str1 = malloc(5);
// char *str2 = malloc(5);
// strcpy(str1, "sort");
// strcpy(str2, "sort");
// BSTreeInsertR(&tree, str1);//插入数据
// BSTreeInsertR(&tree, "tree");//插入数据
// BSTreeInsertR(&tree, str2);//插入数据
// printf("%d\n", BSTreeFindNodeR(tree, "sort"));//查找元素
// //如果用字符串地址比较字符串:将找不到sort ,并且插入两个sort,
// //因为两个sort的地址不一样,所以要用字符串内容进行比较
//
//}
void TestBinaryTranslate()//key 是英文 vulue 是中文
{
BSTreeNode *tree = NULL;
BSTreeInsertR(&tree, "sort","排序");//插入数据
BSTreeInsertR(&tree, "tree","树");//插入数据
BSTreeInsertR(&tree, "pick","选择");//插入数据
BSTreeInsertR(&tree, "sleep", "睡眠");//插入数据
BSTreeInsertR(&tree, "insist", "坚持");//插入数据
char *str = (char *)malloc(128);
while (strcmp(str, "exit") != 0)
{
printf("请输入要查找的单词:\n");
scanf("%s", str);
BSTreeNode *node = BSTreeFindNodeR(tree, str);
if (node)
{
printf("%s\n", node->_value);
}
else
printf("该单词不存在\n");
}
}
void TestBinaryExistNum()//统计关键词出现的次数
{
BSTreeNode *tree = NULL;
char *fruit[] = { "香蕉","哈密瓜","西瓜","樱桃","香蕉","西瓜","哈密瓜","香蕉","菠萝" };
int size = sizeof(fruit) / sizeof(fruit[0]);
for (int i = 0; i < size; i++)
{
BSTreeNode *node = BSTreeFindNodeR(tree, fruit[i]);
if (node == NULL)
{
BSTreeInsertR(&tree, fruit[i], 1);
}
else
node->_value++;
}
BSTreeInOrder(tree);//中序遍历
}
//int main()
//{
// TestBinaryTranslate();
// TestBinaryExistNum();
// system("pause");
// return 0;
//}
Hash.h
#pragma once
typedef char* HTKeyType;
typedef int HTValueType;
enum STATUS
{
EXIST,//该位置有数据
DELETE,//该位置数据被删除
EMPTY,//该位置没有数据
};
typedef struct HashNode
{
HTKeyType _key;//数据
HTValueType _value;
enum STATUS _status;//状态
}HashNode;
typedef struct HashTable
{
HashNode *hash;
size_t _size;//哈希表里有效数据个数
size_t _capacity;//哈希表大小
}HashTable;
void HTInit(HashTable *ht, int capacity);//哈希表初始化
//成功:0,失败-1
int HTInsert(HashTable *ht, HTKeyType key, HTValueType value);//插入数据
HashNode* HTFind(HashTable *ht, HTKeyType key);//查找
int HTRemove(HashTable *ht, HTKeyType key);//删除
void HTPrint(HashTable ht);//打印哈希表
void HTDestroy(HashTable *ht);//销毁哈希表
Hash.c
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
#include"Hash.h"
//void TestHashTable()
//{
// HashTable ht;
// HTInit(&ht,11);//哈希表初始化
// HTInsert(&ht, "pick");
// HTInsert(&ht, "sleep");
// HTInsert(&ht, "insist");
// HTPrint(ht);//打印哈希表;
// HTDestroy(&ht);
//}
void TestHashTableNum()
{
HashTable ht;
HTInit(&ht,0);//哈希表初始化
char *fruit[] = { "香蕉","哈密瓜","西瓜","樱桃","香蕉","西瓜","哈密瓜","香蕉","菠萝" };
int size = sizeof(fruit) / sizeof(fruit[0]);
for (int i = 0; i < size; i++)
{
HashNode *node = HTFind(&ht, fruit[i]);
if (node)//已经存在
{
node->_value++;
}
else
HTInsert(&ht, fruit[i], 1);
}
HTPrint(ht);
}
int main()
{
TestHashTableNum();
system("pause");
return 0;
}
int GetPrime(HashTable *ht)
{
const int _PrimeSize = 28;
//该数据都是经过许多人测试的素数,能够满足需求,冲突较小
static const unsigned long _PrimeList[_PrimeSize] = {
53ul,97ul,193ul,389ul,769ul,
1543ul,3079ul,6151ul,12289ul,
24593ul,49157ul,98317ul,196613ul,
393241ul,786433ul,1572869ul,3145739ul,
6291469ul,12582917ul,25165843ul,50331653ul,
100663319ul,201326611ul,402653189ul,805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
int index = 0;
while (index < _PrimeSize)
{
if (ht->_capacity < _PrimeList[index])
{
return _PrimeList[index];
}
index++;
}
return _PrimeList[_PrimeSize - 1];
}
void HTInit(HashTable *ht, int capacity)//哈希表初始化
{
assert(ht);
ht->_size = 0;
ht->_capacity = capacity;
ht->_capacity = GetPrime(ht);//哈希表是素数大小,减少冲突
ht->hash = (HashNode *)malloc(sizeof(HashNode)*ht->_capacity);
assert(ht->hash);
for (int i = 0; i < ht->_capacity; i++)
{
ht->hash[i]._status = EMPTY;//必须初始化状态
}
}
size_t BKDRHash(char *str)//将字符串转成整数,可以取模
{
size_t hash = 0;
while (*str)
{
//hash=hash+*str;// abcd aadd
hash = hash * 131 + *str;//*131冲突概率减少,其他值也可以
str++;
}
return hash;
}
int HashFunc(HashTable * ht, HTKeyType key)
{
return BKDRHash(key) % (ht->_capacity);
}
void CheckCapacity(HashTable *ht)
{
//对于哈希表,并不是size=capacity时才扩容,如果size=capacity,那么当哈希表全部存满时,
//无法用EMPTY判断查找数据,将会陷入死循环
//而是当a=填入表中的数据/哈希表长度>=0.7时就要扩容,a越大,冲突可能性越大
if (ht->_size * 10 / ht->_capacity >= 7)//负载因子大于0.7,需要扩容
{
//扩容:重新定义一个哈希表,将ht里的数据重新插入到newht,不能直接拷贝数据,
//因为newht的表长发生变化,数据存放的位置也将发生变化
HashTable newht;
HTInit(&newht, ht->_capacity * 2);
for (int i = 0; i < ht->_capacity; i++)
{
if (ht->hash[i]._status == EXIST)//必须加上
HTInsert(&newht, ht->hash[i]._key,1);//插入数据
}
free(ht->hash);
ht->hash = newht.hash;
ht->_size = newht._size;
ht->_capacity = newht._capacity;
}
}
int HTInsert(HashTable *ht, HTKeyType key, HTValueType value)//插入数据
{
assert(ht);
CheckCapacity(ht);//判断容量
int index = HashFunc(ht, key);
int i = 1;
while (ht->hash[index]._status == EXIST)//冲突,
{
int tmp = index;
if (ht->hash[index]._key == key)
return -1;
index++;
if (index == ht->_capacity)
index = 0;//线性探测
//二次探测
/*index = tmp + i*i;
i++;
index = index%ht->_capacity;*/
}
ht->hash[index]._key = key;
ht->hash[index]._value = value;
ht->_size++;
ht->hash[index]._status = EXIST;
return 0;
}
void HTPrint(HashTable ht)//打印哈希表
{
for (int i = 0; i < ht._capacity; i++)
{
if (ht.hash[i]._status == EXIST)
printf("[EXIST:%s %d] ", ht.hash[i]._key,ht.hash[i]._value);
/* else if (ht.hash[i]._status == DELETE)
printf("DELETE:%s ", ht.hash[i]._key);
else
printf("EMPTY:NULL ");*/
}
printf("\n");
}
HashNode *HTFind(HashTable *ht, HTKeyType key)//查找
{
assert(ht);
int index = HashFunc(ht, key);
while (ht->hash[index]._status != EMPTY)
{
if (ht->hash[index]._key == key)
{
if (ht->hash[index]._status == EXIST)
return &(ht->hash[index]);
else//状态是删除且值相等,index后不会再存在该数据,直接返回
return NULL;
}
index++;
if (index == ht->_capacity)
index = 0;
}
return NULL ;
}
int HTRemove(HashTable *ht, HTKeyType key)//删除
{
assert(ht);
int index = HashFunc(ht, key);
while (ht->hash[index]._status != EMPTY)
{
if (ht->hash[index]._key == key)
{
if (ht->hash[index]._status == EXIST)
{
ht->hash[index]._status = DELETE;
ht->_size--;
}
else
return -1;//该数据已经被删除,无法再删除
}
index++;
if (index == ht->_capacity)
index = 0;
}
return -1;//没有找到该数据,删除失败
}
void HTDestroy(HashTable *ht)//销毁哈希表
{
assert(ht);
free(ht->hash);
ht->hash = NULL;
ht->_capacity = 0;
ht->_size = 0;
}