C语言 手写HashMap实验

使用c语言,实现一个HashMap的数据结构,"该HashMap与JAVA语言中的HashMap有相似的功能,利用链表和红黑树等数据结构,实现O(1)时间的复杂度进行插入,删除等操作,具体包括put、get、resize、remove、treeifyBin方法。
当<k,v>键值对达到7以上,要调用treeifyBin方法实现链表转化为红黑树存储"

// 定义哈希表中的节点结构
typedef struct Node {
    char *key;
    int value;
    struct Node *next;
} Node;

typedef enum {
    Link,
    RED_BLACK_TREE
} BucketType;

// 定义哈希表结构
typedef struct {
    int capacity;
    int size;
    Node **buckets;
    BucketType *bucket_types;  // 新增的标记桶数据结构类型的成员
} HashMap;

// 定义红黑树节点结构
typedef struct RBNode {
    char *key;
    int value;
    struct RBNode *left;
    struct RBNode *right;
    struct RBNode *parent; // 添加指向父节点的指针
    int color; // 0 for Black, 1 for Red
} RBNode;

//创建哈希表
HashMap *createHashMap() {
    HashMap *map = (HashMap *) malloc(sizeof(HashMap));
    map->capacity = INITIAL_CAPACITY;
    map->size = 0;
    map->buckets = (Node **) calloc(map->capacity, sizeof(Node *));
    map->bucket_types = (BucketType *) calloc(map->capacity, sizeof(BucketType)); // 初始化 bucket_types 数组
    for (int i = 0; i < map->capacity; ++i) {
        map->buckets[i] = NULL;
        map->bucket_types[i] = Link;  // 初始情况下,所有桶都被标记为列表类型
    }
    return map;
}


// 重载的方法  可以传递容量大小 用于初始化
HashMap *createHashMapS(int capacity) {
    HashMap *map = (HashMap *) malloc(sizeof(HashMap));
    map->capacity = capacity;
    map->size = 0;
    map->buckets = (Node **) calloc(map->capacity, sizeof(Node *));
    map->bucket_types = (BucketType *) calloc(map->capacity, sizeof(BucketType)); // 初始化 bucket_types 数组
    for (int i = 0; i < map->capacity; ++i) {
        map->buckets[i] = NULL;
        map->bucket_types[i] = Link;  // 初始情况下,所有桶都被标记为列表类型
    }
    return map;
}

// 散列函数
int hash(char *key, int capacity) {
    int hash = 0;
    while (*key) {
        hash = (hash * 31 + *key) % capacity;
        key++;
    }
    return hash;
测试红黑树 一直添加到桶序号为10的下面
//    return 10;
}

// 计算红黑树节点数量
int countNodes(RBNode *root) {
    if (root == NULL) {
        return 0;
    }
    // 递归计算左子树和右子树的节点数量,并加上根节点
    return 1 + countNodes(root->left) + countNodes(root->right);
}

// 计算指定桶的大小
int bucketSize(HashMap *map, int index) {
    if (index < 0 || index >= map->capacity) {
        return 0;
    }

    int count = 0;
    BucketType bucket_type = map->bucket_types[index];
    //如果是红黑树结点
    if (bucket_type == RED_BLACK_TREE) {
        RBNode *root = (RBNode *) map->buckets[index];
        return countNodes(root);
    } else {
        Node *node = map->buckets[index];
        while (node) {
            count++;
            node = node->next;
        }
        return count;
    }
}

// 从红黑树中获取值
int getValueFromRedBlackTree(RBNode *root, char *key) {
    // 遍历红黑树,查找对应的键值对
    while (root != NULL) {
        int cmp = strcmp(key, root->key);
        if (cmp == 0) {
            return root->value; // 找到对应的键值对,返回值
        } else if (cmp < 0) {
            root = root->left; // 当前键值小于根节点的键值,移动到左子树继续查找
        } else {
            root = root->right; // 当前键值大于根节点的键值,移动到右子树继续查找
        }
    }
    return -1; // 未找到对应键的值
}

// 从哈希表中获取值
int get(HashMap *map, char *key) {
    int index = hash(key, map->capacity);
    BucketType bucket_type = map->bucket_types[index];
    if (bucket_type == RED_BLACK_TREE) {
        RBNode *root = map->buckets[index];
        //通过对红黑树树的遍历查找对应的key
        return getValueFromRedBlackTree(root, key);
    } else {
        Node *node = map->buckets[index];
        while (node) {
            if (strcmp(node->key, key) == 0) {
                return node->value;
            }
            node = node->next;
        }
        return -1; // 未找到对应键的值
    }
}

// 释放红黑树内存(辅助函数)
void freeRBTree(RBNode *root) {
    if (root == NULL) {
        return;
    }
    freeRBTree(root->left);
    freeRBTree(root->right);
    free(root->key);
    free(root);
}


// 左旋
void rotateLeft(RBNode **root, RBNode *node) {
    RBNode *rightChild = node->right;
    node->right = rightChild->left;
    if (node->right != NULL) {
        node->right->parent = node; // 这里需要更新右子节点的父节点指针
    }
    rightChild->parent = node->parent; // 更新右子节点的父节点指针
    if (node->parent == NULL) {
        *root = rightChild;
    } else if (node == node->parent->left) {
        node->parent->left = rightChild;
    } else {
        node->parent->right = rightChild;
    }
    rightChild->left = node;
    node->parent = rightChild;
}


// 右旋
void rotateRight(RBNode **root, RBNode *node) {
    RBNode *leftChild = node->left;
    node->left = leftChild->right;
    if (node->left != NULL) {
        node->left->parent = node;
    }
    leftChild->parent = node->parent;
    if (node->parent == NULL) {
        *root = leftChild;
    } else if (node == node->parent->left) {
        node->parent->left = leftChild;
    } else {
        node->parent->right = leftChild;
    }
    leftChild->right = node;
    node->parent = leftChild;
}


// 红黑树插入修正
void insertFixup(RBNode **root, RBNode *node) {
    while (node != NULL && node != *root && node->parent->parent != NULL && node->parent->color == 1) {
        // 如果当前节点的父节点是祖父节点的左孩子
        //相当于需要右旋了
        if (node->parent == node->parent->parent->left) {
            RBNode *uncle = node->parent->parent->right; // 获取当前节点的叔节点
            // 情况1:叔节点也为红色
            if (uncle != NULL && uncle->color == 1) {
                node->parent->color = 0; // 将父节点设为黑色
                uncle->color = 0; // 将叔节点设为黑色
                node->parent->parent->color = 1; // 将祖父节点设为红色
                node = node->parent->parent; // 将当前节点指向祖父节点,继续向上修正
            } else {
                // 情况2:当前节点为父节点的右孩子
                if (node == node->parent->right) {
                    node = node->parent; // 将当前节点指向父节点
                    rotateLeft(root, node); // 左旋
                }
                node->parent->color = 0; // 将父节点设为黑色
                if (node->parent->parent != NULL) {
                    node->parent->parent->color = 1; // 将祖父节点设为红色
                    rotateRight(root, node->parent->parent); // 右旋
                }
            }
        } else {
            // 如果当前节点的父节点是祖父节点的右孩子(与上述情况对称)
            RBNode *uncle = node->parent->parent->left;
            // 情况1:叔节点也为红色
            if (uncle != NULL && uncle->color == 1) {
                node->parent->color = 0; // 将父节点设为黑色
                uncle->color = 0; // 将叔节点设为黑色
                node->parent->parent->color = 1; // 将祖父节点设为红色
                node = node->parent->parent; // 将当前节点指向祖父节点,继续向上修正
            } else {
                // 情况2:当前节点为父节点的左孩子(与上述情况对称)
                if (node == node->parent->left) {
                    node = node->parent; // 将当前节点指向父节点
                    rotateRight(root, node); // 右旋
                }
                node->parent->color = 0; // 将父节点设为黑色
                if (node->parent->parent != NULL) {
                    node->parent->parent->color = 1; // 将祖父节点设为红色
                    rotateLeft(root, node->parent->parent); // 左旋
                }
            }
        }
    }
    (*root)->color = 0; // 根节点始终为黑色
}


// 将链表转换为红黑树
void treeifyBin(HashMap *map, int index) {

源码:

百度链接 

https://pan.baidu.com/s/1ZqQ0XxOQ_mFaXWempYpB3w?pwd=rwfl 
提取码:rwfl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值