哈希表、二叉搜索树key和key value(判断是否存在、字典.....)

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;
}

这里写图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值