源码解析系列:HashMap(5) - c语言实现一个HashMap


1. 前言

HashMap(5)中主要介绍了我的一个数据结构实验课设,而这个课设是实现一个HashMap,政整个HashMap的实现是以java JDK1.8的HashMap为参考实现的,其实说是参考,大部分其中的方法是和java源码一样的,在红黑树的方面则是自己设计的。对于这个课设,也有一些和HashMap不一样的地方,比如Key和Value都是使用int类型的,数组下标不再存放无头单链表,而是存放有头单链表,这其实都是其中一些坑,后来慢慢改成这样的。对于HashMap的学习,我一直都是认为尽管看了10遍都不如自己动手敲1遍,好记性不如烂笔头是真的。敲完一遍之后自己对底层的一些设计是比较有清晰的一个认识的,尤其是扩容处理和红黑树树化处理这块,也是做了一个HashMap课设之后才知道原来在树化的时候不仅仅维护了树,还维护了双向链表。以及其中一些常量的设计,都会有一个全新的认识。
第一篇文章:源码解析系列:HashMap(1)
第二篇文章:源码解析系列:HashMap(2)
第三篇文章:源码解析系列:HashMap(3)
第四篇文章:源码解析系列:HashMap(4)
第五篇文章:源码解析系列:HashMap(5)



2. 开始C语言之旅

话不多说了,直接上代码,代码中都有很详细的解析了,不需要再多讲。使用工具:VS2019,把代码复制到VS里直接运行即可。

1、常量头文件Common.h

#define _CRT_SECURE_NO_WARNINGS
#ifndef  aaa
#define aaa
#endif // ! aaa

//常用头文件
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include <time.h>
#include<float.h>
#include<math.h>


//常用常量
#define OK 1
#define ERROR 0
#define MYOVERFLOW -1
#define ARGS_ERROR -2
#define TRUE 1
#define FALSE -0
//默认初始化容量
#define DEFAULT_INITIAL_CAPACITY 1<<4	//16
//字符串大小
#define STR_MAX_SIZE 1024
//最大的容量
#define MAXIMUM_CAPACITY 1<<30		//1073741824
//int最大容量
#define INT_MAX 2147483647		
//不存在,专门对于那些不存在的结点使用的
#define UN_EXIT -2147483648	
//负载因子
#define DEFAULT_LOAD_FACTOR 0.75
//树化条件
#define TREEIFY_THRESHOLD 8
//红色
#define RED 1
//黑色
#define BLACK 0
//最小扩容树的长度 64
//测试
#define MIN_TREEIFY_CAPACITY 6
//去树化的最大值
#define UNTREEIFY_THRESHOLD 6


//常用类型定义
typedef int Status;
typedef int key;
typedef int Key;
typedef int Value;
//typedef int rcdType;#pragma once


2、map头文件,包含方法以及结构体的定义

#include "Common.h"
typedef struct {
	Key key;  //键
	Value value;  //值
	int hashCode;//hashCode
	int hash;	 //hash
}DataType; //对基本数据类型进行封装,类似泛型

//结点
typedef struct hashnode{
	DataType data;
	int isRed;				//红色还是黑色
	struct hashnode* next, *prev;  //key冲突时,通过next指针进行连接, prev:树化的时候使用
	struct hashnode* lchild, *rchild, *parent;	//树化的时候通过这个连接
}HashNode, *hashNode;

typedef struct {
	//负载因子
	float loadFactor;
	//键值对大小
	int size;
	//修改次数
	int modCount;
	//扩容阈值: 容量(桶数量)* 负载因子
	int threshold;
	//桶的长度
	int length;
	//桶
	HashNode* table;
}HashMap, *hashmap;


//菜单
void meun();

/*
*工具方法
*/
//计算hashCode
int hashCode(char* a);
//计算char的长度
int findLength(char* c);
//求初始容量:2的n次方
int numberOfLeadingZeros(unsigned int i);
int tableSizeFor(int cap);
//计算hash
int hash(hashNode node);
//通过key计算hash
int hashByKey(Key key);
//判断浮点数合不合理
const int show_classification(float x);
//根据key和value封装node
hashNode package(Key key, Value value);
//判断两个key是不是相同的
Status equals(Key var1, Key var2);
//比较两个key大小
Status compare(Key var1, Key var2);
//两个结点赋值
void initByOther(HashNode& node1, hashNode& node2);
//对链表进行清除
void clear(hashNode table);


/*
	开始构建hashMap,三种构造方法
*/
int init1(hashmap& hashMap);

int init2(hashmap& hashMap,int capacity);

int init3(hashmap& hashMap, int initialCapacity, float loadFactor);

//判断hashmap是不是空
int isEmpty(hashmap hashMap);

//获取键值对的数量
int size(hashmap hashMap);

//根据键key获取value
Value get(Key key, hashmap hashMap);

//根据hash和key获取结点
hashNode getNode(int hash, Key key, hashmap hashMap);

//put加入结点,可以进行替换
Status put(Key key, Value value, hashmap& hashMap);

//put加入结点,不可以进行替换
Status putNotReplace(Key key, Value value, hashmap& hashMap);

//统一加入的结点
/**
		hash:hash值
		key:键
		value:值
		onlyIfAbsent:当这个参数为1的时候,表示同key情况下不可被覆盖
		evict:用于linkHashmap的,这里不要求
*/
Status putVal(int hash, Key key, Value value, int onlyIfAbsent,
	int evict, hashmap& hashMap);

//分配空间
hashNode resize(hashmap& hashMap);

//清空hashMap
void clear(hashmap &hashMap);

//hashMap是否包含某个key
Status containsKey(Key key, hashmap& hasmMap);

//hashMap是否包含某个Value
Status containsValue(Value value, hashmap hashMap);

//真正的remove方法
Status removeNode(int hash, Key key, Value value, int matchValue, int movable, hashmap &hashMap);

//通过key和value进行移除
Status removeByKeyValue(Key key, Value value, hashmap& hashMap);
//通过key移除
Value removeByKey(Key key, hashmap& hashMap);

//替换
Status replaceByKeyValue(Key key, Value oldValue, Value newValue, hashmap& hashMap);

//根据key来进行匹配
Status replaceByKey(Key key, Value newValue, hashmap& hashMap);

//初始树化操作
hashNode treeifBin(hashNode table, int hash, hashmap hashMap);
//树化
hashNode treeif(hashNode node, hashNode table, int hash, hashmap hashMap);
//重新对root根节点赋值
void moveRootToFront(hashNode& table, hashNode root, hashmap hashMap);
//检测红黑树是否规范
void checkInvariants(hashNode root);

//对红黑树结点进行分流
void split(hashNode& node, hashmap& hashmap, hashNode& tab, int index, int bit, int oldCap);

//去树化
hashNode untreeify(hashmap hashMap, hashNode node);
//树结点转化成链表节点
hashNode beTreeToNode(hashNode p);


3、树的头文件,包含方法


/*
	红黑树接口
*/
#include "map.h"

//求父节点
hashNode parentOf(hashNode node);

//判断结点是不是红色的
int RedOrNot(hashNode node);
int isBlack(hashNode node);

//中序打印
void inOrderPrint(hashNode root);
void inOrderPrint_1(hashNode root);

//获取根节点
hashNode getRoot(hashNode root);

//左旋
void leftRotate(hashNode& root, hashNode x);

//右旋
void rightRotate(hashNode& root, hashNode x);

//插入方法
void insert(Key key, Value value, hashNode& root, hashmap& hashMap);
//插入
void insertReal(hashNode node, hashNode& root, hashmap& hashMap);
//插入修复
void insertFixUp(hashNode& node, hashNode& root);

//删除叶子结点
void deleteNode(hashmap& hashmap, int hash, Key key, Value value, hashNode& root, hashNode node);
//真正的删除
void deleteNodeReal(hashNode node, hashNode& root, hashmap& hashMap);
//删除修复
void deleteFixUp(hashNode x, hashNode parent, hashNode& root);

//删除的辅助方法
//1. 子树替换
void transplate(hashNode u, hashNode v, hashNode& root);

//2.查找最小的元素
hashNode searchNode(Value key, hashNode root);

//3. 最小关键字元素 
hashNode searchMin(hashNode root);

/**
 * 画树函数
 */
void draw_level(hashNode* node, bool left, char* str); // 画分支
void draw(hashNode* root);                             // 画根节点
void drawLine(hashNode root);						   // 链表的打印
void print(hashNode table, hashmap hashMap);							   // hashmap的打印

4、main.h,主函数.h

#include "RBTree.h"

int main(void) {
	hashmap hashMap = NULL;
	meun();
	char want;
	while (1) {
		printf("请输入选择(输入g显示菜单):");
		while ((want = getchar()) != '\n' && want != EOF) {
			switch (want) {
				case 'a': {
					if (init1(hashMap) != OK) {
						printf("初始化失败(已初始化或者异常)\n");
						break;
					}
					printf("初始化成功\n");
					break;
				}
				case 'b': {
					int capacity = 0;
					printf("请输入扩容阈值:");
					scanf("%d", &capacity);
					if (capacity < 0 || init2(hashMap, capacity) != OK) {
						printf("初始化失败(已初始化或者异常)\n");
						break;
					}
					printf("初始化成功\n");
					break;
				}
				case 'c': {
					int capacity = 0;
					printf("请输入扩容阈值:");
					scanf("%d", &capacity);
					float loadFactor = 0;
					printf("请输入负载因子:");
					scanf("%f", &loadFactor);
					if (capacity < 0 || loadFactor < 0.0 || init3(hashMap, capacity, loadFactor) != OK) {
						printf("初始化失败(已初始化或者异常)\n");
						break;
					}
					printf("初始化成功\n");
					break;
				}
				case 'd': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value value = 0;
					printf("请输入value:");
					scanf("%d", &value);
					Status result = put(key, value, hashMap);
					if (result == ERROR) {
						printf("插入失败\n");
						break;
					}
					printf("插入成功\n");
					break;
				}
				case 'e': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value value = 0;
					printf("请输入value:");
					scanf("%d", &value);
					Status result = putNotReplace(key, value, hashMap);
					if (result == ERROR) {
						printf("插入失败\n");
						break;
					}
					printf("插入成功\n");
					break;
				}
				case 'f': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
				    Status result = containsKey(key, hashMap);
					if (result == OK) {
						printf("包含该key\n");
						break;
					}
					else {
						printf("不包含该key\n");
						break;
					}
				}
				case 'g': {
					meun();
					break;
				}
				case 'h': {
					if (hashMap == NULL || hashMap->table == NULL) {
						printf("没有结点\n");
						break;
					}
					print(hashMap->table, hashMap);
					break;
				}
				case 'i': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value oldValue = 0;
					printf("请输入新的value值:");
					scanf("%d", &oldValue);
					if (replaceByKey(key, oldValue, hashMap) == ERROR) {
						printf("替换失败\n");
						break;
					}
					printf("替换成功\n");
					break;
					break;
				}
				case 'j': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value value = get(key, hashMap);
					if (value == UN_EXIT) {
						printf("没有找到\n");
						break;
					}
					printf("找到了对应得value,value=%d\n", value);
					break;
				}
				case 'k': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value oldValue = 0;
					printf("请输入value值:");
					scanf("%d", &oldValue);
					Value newValue = 0;
					printf("请输入替换后的value值:");
					scanf("%d", &newValue);
					if (replaceByKeyValue(key, oldValue, newValue, hashMap) == ERROR) {
						printf("替换失败\n");
						break;
					}
					printf("替换成功\n");
					break;
				}
				case 'l': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value value = removeByKey(key, hashMap);
					if (value == ERROR) {
						printf("删除失败\n");
						break;
					}
					printf("删除成功\n");
					break;
				}
				case 'm': {
					Key key = 0;
					printf("请输入key:");
					scanf("%d", &key);
					Value value = 0;
					printf("请输入value值:");
					scanf("%d", &value);
					Status result = removeByKeyValue(key, value, hashMap);
					if (result == ERROR) {
						printf("删除失败\n");
						break;
					}
					printf("删除成功\n");
					break;
				}
				case 't': {
					for (int i = 11; i <= 99; i += 11) {
						put(i, i, hashMap);
					}
					break;
				}
				case 'u': {
					for (int i = 99; i >= 66; i -= 11) {
						removeByKey(i, hashMap);
					}
					break;
				}
				default:break;
			}
		}
	}
	return 0;
}

5、map.cpp,实现map.h头文件里面的函数

#include "RBTree.h"


/*
    工具方法
*/
int hashCode(char* a) {
    if (a == NULL) {
        return 0;
    }
    else {
        int result = 1;
        char* var1 = a;
        int var2 = findLength(a);

        for (int var3 = 0; var3 < var2; ++var3) {
            char element = var1[var3];
            result = 31 * result + element;
        }

        return result;
    }
}

//查找长度
int findLength(char* c) {
    int sum = 0;
    for (sum; c[sum] != '\0'; sum++) {
        sum++;
    }
    return sum;
}

//求有多少个0
int numberOfLeadingZeros(unsigned int i) {
    if (i <= 0) {
        return i == 0 ? 32 : 0;
    }
    else {
        int n = 31;
        if (i >= 65536) {
            n -= 16;
            i >>= 16;
        }

        if (i >= 256) {
            n -= 8;
            i >>= 8;
        }

        if (i >= 16) {
            n -= 4;
            i >>= 4;
        }

        if (i >= 4) {
            n -= 2;
            i >>= 2;
        }

        return n - (i >> 1);
    }
}

//求容量大小
int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >> 1;
    n |= n >> 2;
    n |= n >> 4;
    n |= n >> 8;
    n |= n >> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

//求结点的左子树
hashNode getLeft(hashNode node) {
    return node->lchild;
}

//求结点的右子树
hashNode getRight(hashNode node) {
    return node->rchild;
}

//判断颜色,红色:1,黑色:0
int isRed(hashNode node) {
    return node->isRed;
}

//判断两个key是不是相同的
Status equals(Key var1, Key var2) {
    return var1 == var2 ? OK : ERROR;
}

//比较两个key的大小
//-1,第2个大,0,相同,1,第1个大
Status compare(Key var1, Key var2) {
    if (var1 > var2) {
        return 1;
    }
    else if (var1 == var2) {
        return 0;
    }
    else {
        return -1;
    }
}

//封装key value
hashNode package(Key key, Value value) {
    char temp[STR_MAX_SIZE] = {0};
    //把一个数转化成10进制字符串求hashCode
    _itoa(key, temp, 10);
    hashNode node = (hashNode)malloc(sizeof(HashNode));
    //key一定不为NULL
    if (node == NULL || key == NULL) {
        return NULL;
    }
    node->lchild = NULL;
    node->rchild = NULL;
    node->next = NULL;
    node->prev = NULL;
    node->parent = NULL;
    //加入的结点一定为红色结点
    node->isRed = RED;
    node->data.key = key;
    node->data.value = value;
    //加入hashCode
    node->data.hashCode = hashCode(temp);
    //加入hash值
    node->data.hash = hash(node);
    return node;
}


//求hash
int hash(hashNode node) {

    unsigned int h;
    return (node == NULL) ? 0 : (h = node->data.hashCode) ^ (h >> 16);
}

//通过key计算hash
int hashByKey(Key key) {
    char temp[STR_MAX_SIZE] = {0};
    //把一个数转化成10进制字符串求hashCode
    _itoa(key, temp, 10);
    unsigned int h;
    return (key == NULL) ? 0 : (h = hashCode(temp)) ^ (h >> 16);
}

//判断一个浮点数是不是合法的
const int show_classification(float x)
{
    switch (fpclassify(x))
    {
    case FP_INFINITE:
       
    case FP_NAN:
       
    case FP_NORMAL:return OK;
       
    case FP_SUBNORMAL:
       
    case FP_ZERO:
        return ARGS_ERROR;
    default:
        return -1;
        break;
    }
}


/*
    开始构建hashMap
*/
//默认参数
int init1(hashmap& hashMap){
    if (hashMap != NULL) {
        return ERROR;
    }
    hashMap = (hashmap)malloc(sizeof(HashMap));
    if (hashMap == NULL) {
        return MYOVERFLOW;
    }
    //初始化默认的16和0.75
    hashMap->loadFactor = DEFAULT_LOAD_FACTOR;
    hashMap->length = 0;
    hashMap->modCount = 0;
    hashMap->size = 0;
    //懒加载
    hashMap->table = NULL;
    hashMap->threshold = 0;
    return OK;
}

//自定义容量
int init2(hashmap& hashMap, int capacity) {
    if (hashMap != NULL || capacity <= 0) {
        return ERROR;
    }
    return init3(hashMap, capacity, DEFAULT_LOAD_FACTOR);
}

//自定义容量和负载因子
int init3(hashmap& hashMap, int initialCapacity, float loadFactor) {
    if (hashMap != NULL || initialCapacity <= 0 || loadFactor <= 0.0) {
        return ERROR;
    }
    //参数判断
    hashMap = (hashmap)malloc(sizeof(HashMap));
    if (hashMap == NULL) {
        return MYOVERFLOW;
    }
    //初始容量不合理
    if (initialCapacity < 0 || initialCapacity > MAXIMUM_CAPACITY) {
        return ARGS_ERROR;
    }

    //负载因子不合理
    if (loadFactor <= 0 || show_classification(loadFactor) == ARGS_ERROR) {
        return ARGS_ERROR;
    }

    hashMap->loadFactor = loadFactor;
    //2的n次方
    hashMap->threshold = tableSizeFor(initialCapacity);
    hashMap->length = 0;
    hashMap->modCount = 0;
    hashMap->table = NULL;
    hashMap->size = 0;
    return OK;
}

//map是不是空
int isEmpty(hashmap hashMap) {
    return hashMap->size == 0 ? 1 : 0;
}

//获取键值对的数量
int size(hashmap hashMap) {
    return hashMap->size;
}

//根据key获取value
Value get(Key key, hashmap hashMap) {
    if (key == UN_EXIT || hashMap == NULL) {
        return UN_EXIT;
    }
    hashNode node;
    hashNode temp = package(key, NULL);
    return (node = getNode(hash(temp), key, hashMap)) == NULL ? UN_EXIT : node->data.value;
}

//获取结点
hashNode getNode(int hash, Key key, hashmap hashMap)  {
    if (key == UN_EXIT && hashMap == NULL) {
        return NULL;
    }
    //先获取所有的桶
    hashNode table = NULL;
    hashNode first, e;
    int length = 0; 
    Key k = NULL;
    if ((table = hashMap->table) != NULL && ((length = hashMap->length) != 0)
        && ((first = &(table[(length - 1) & hash]))) != NULL
        && first->data.key != UN_EXIT) {
        //带头的链表
        first = first->next;
        //证明有结点,并且根据key找到了本来在哪个下标
        if (first->data.hash == hash && equals(key, first->data.key) == OK) {
            return first;
        }
        //如果是树
        if (first->lchild != NULL || first->rchild != NULL) {
            //左子树或者右子树不是空,证明此时是树,使用树的查找
            return searchNode(key, first);
        }

        //否则证明是链表
        //不是第一个结点
        if ((e = first->next) != NULL) {
            //存在下一个结点,遍历查找
            do {
                if (e->data.hash == hash &&
                    ((k = e->data.key) == key || (key != NULL && equals(key, k)))) {
                    return e;
                }
            } while ((e = e->next) != NULL);
        }
    }
    return NULL;
}

//put加入结点,可以进行替换
Status put(Key key, Value value, hashmap &hashMap) {
    if (hashMap == NULL || key == UN_EXIT || value == UN_EXIT) {
        return NULL;
    }
    hashNode node = getNode(hashByKey(key), key, hashMap);
    //如果存在,就直接替换
    if (node != NULL) {
        node->data.value = value;
        return OK;
    }
    return putVal(hashByKey(key), key, value, FALSE, FALSE, hashMap);
}

Status putNotReplace(Key key, Value value, hashmap& hashMap) {
    if (hashMap == NULL || key == UN_EXIT || value == UN_EXIT) {
        return NULL;
    }
    hashNode node = getNode(hashByKey(key), key, hashMap);
    //如果存在,就返回错误
    if (node != NULL) {
        return ERROR;
    }
    return putVal(hashByKey(key), key, value, TRUE, FALSE, hashMap);
}

//统一加入的结点
/**
        hash:hash值
        key:键
        value:值
        onlyIfAbsent:当这个参数为1的时候,表示同key情况下不可被覆盖
        evict:用于linkHashmap的,这里不要求
*/
Status putVal(int hash, Key key, Value value, int onlyIfAbsent,
    int evict, hashmap &hashMap) {
    Value oldValue = NULL;
    hashNode tab;
    //tableLength:表的长度
    //i:数组下标
    hashNode first; int tableLength, i;
    //判断hashMap是不是空,如果是空,证明是第一次进入的
    if ((tab = hashMap->table) == NULL || (tableLength = hashMap->length) == 0) {
        //开始初始化hashMap的table
        tab = resize(hashMap);
        tableLength = hashMap->length;
        hashMap->table = tab;
    }
    //i:下标
    i = (tableLength - 1) & hash;
    hashNode root = hashMap->table[i].next;
    //把tab[i]的开头赋值给first
    if ((first = &tab[i])->data.key == UN_EXIT) {
        //如果是空,证明该下标没有数据
        tab[i].next = package(key, value);
        //改成0,防止下次还进来
        tab[i].data.key = 0;
    }
    else {
        //证明有数据
        //有头单链表
        first = first->next;
        hashNode e = NULL;
        Key key1 = UN_EXIT;
        //hash相同,key又相同,key赋值
        if (first->data.hash == hash && equals(first->data.key, key)) {
            e = first;
        }
        else if (first->lchild != NULL || first->rchild != NULL) {
            //树
            insert(key, value, root, hashMap);
        }
        else {
            //链表
            for (int binCount = 0; ; binCount++) {
                e = first->next;
                if (e == NULL) {
                    first->next = package(key, value);
                    //如果大于8,就开始树化
                    if (binCount >= TREEIFY_THRESHOLD - 1) {
                        // 树化
                        tab = treeifBin(tab, hash, hashMap);
                    }
                    break;
                }
                //如果找到一个相同的,就直接break替换
                if (e->data.hash == hash && equals(key, first->data.key)) {
                    break;
                }
                first = e;
            }
        }
        //到了这里,e不为空,证明中途找到了一模一样的key,进行替换
        if (e != NULL) {
            Value oldValue = e->data.value;
            //onlyIfAbsent为0的时候或者这个值是空的才可以替换
            if (!onlyIfAbsent || oldValue == NULL){
                //进行替换
                e->data.value = value;
                return OK;
            }
        }
    }
    //添加修改次数
    hashMap->modCount++;
    //kv个数+1
    hashMap->size++;
    //超出界限
    if (hashMap->size > hashMap->threshold) {
        //重新分配空间
        tab = resize(hashMap);
    }
    hashMap->table = tab;
    //重新指向新的table
    return OK;
}

//重新分配空间,改变存储结构
hashNode resize(hashmap &hashMap) {
    //旧数组
    hashNode oldTab = hashMap->table;
    //旧的数组长度
    int oldCap = hashMap->length;
    //旧的扩容阈值
    int oldThr = hashMap->threshold;
    //新的数组长度和新的容量
    int newCap, newThr = 0;
    //正常扩容,数组中有长度了
    if (oldCap > 0) {
        //旧的容量(数组长度)大于0,证明已经初始化了
        if (oldCap > MAXIMUM_CAPACITY) {
            //如果容量已经大于最大的了,阈值直接设置成最大的,不再扩容了
            hashMap->threshold = INT_MAX;
            return oldTab;
        }
        //判断如果新的长度大小为旧的扩展一倍,并且小于最大的容量值,16是默认的初始容量,也可以自定义容量,使用init1时可以这样扩容
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) {
            newThr = oldThr << 1;
        }
    }
    //oldCap = 0, oldThr不等于0,else if和else都是初始化
    //容量为0但是阈值大于0对应java的有默认值得构造函数
    //1. new HashMap(initCap, loadFactory)
    //2. new HashMap(initCap)
    else if (oldThr > 0) {
        //新的长度大小=旧的阈值
        newCap = oldThr;
    }
    //init1()
    else {
        //两个都是0,证明是刚刚初始化
        newCap = 16;
        newThr = 12;
    }

    //对应HashMap中的以下情况
    //1. new HashMap(initCap, loadFactory)
    //2. new HashMap(initCap)
    //3. new HashMap(map) 并且这个map有数据
    //4. oldCap < 16
    //newThr为0时,通过newCap和负载因子计算出一个newThr
    if (newThr == 0) {
        float ft = (float)newCap * hashMap->loadFactor;
        //大部分都是相乘取整了
        newThr = newCap < 1073741824 && ft < 1.07374182E9F ? (int)ft : 2147483647;
        if (newThr == 0) {
            //防止相乘得到的结果是空的情况
            newThr = 1;
        }
    }
    //赋值给新的扩容的阈值以及新的容量
    hashMap->threshold = newThr;

    //开始扩容
    //经过计算,当16->32之后,原来16上面一部分会分到32上面
    //创建
    hashNode newTab = (hashNode)malloc(newCap * sizeof(HashNode));
    if (newTab == NULL) {
        return NULL;
    }
    //防止野指针
    for (int i = 0; i < newCap; i++) {
        newTab[i].data.hash = 0;
        newTab[i].data.hashCode = 0;
        newTab[i].isRed = RED;
        newTab[i].data.key = UN_EXIT;
        newTab[i].data.value = UN_EXIT;
        newTab[i].next = NULL;
        newTab[i].prev = NULL;
        newTab[i].lchild = NULL;
        newTab[i].rchild = NULL;
        newTab[i].parent = NULL;
    }
    //复制长度
    hashMap->length = newCap;

    //旧的不为空,证明原来的旧表有数据
    if (oldTab != NULL) {
        for (int j = 0; j < oldCap; j++) {
            hashNode node;
            //有数据
            if ((node = &(oldTab[j])) != NULL && node->data.key != UN_EXIT) {
                //证明有头单链表有数据
                node = node->next;
                if (node->next == NULL) { 
                    //证明只有一个头
                    //node->data.hash & (newCap - 1)计算出新节点的地址
                    //由于newCap = oldCap*2,所以其余位不变,比如16->32,多了一个第五位,所以第五位是1,新下标+16,是0,就保留在旧下标
                    newTab[node->data.hash & (newCap - 1)].next = node;
                    //标志位设置为0
                    newTab[node->data.hash & (newCap - 1)].data.key = 0;
                }
                else if (node->lchild != NULL || node->rchild != NULL) {
                    //此时是树,调用树的更新,低位到高位
                    split(node, hashMap, newTab, j, newCap, oldCap);

                }else{
                    //链表
                    //1. 低位链表头和尾
                    //低位链表:存放在扩容之后的数组的下标和原来的数组的下标位置一样
                    hashNode loHead = NULL, loTail = NULL;
                    //2. 高位链表头和尾
                    //高位链表:存放在扩容之后的数组的下标为当前数组下标位置+扩容前数
                    hashNode hiHead = NULL, hiTail = NULL;
                    hashNode next = NULL;
                    while (node != NULL) {
                        next = node->next;
                        //判断:oldCap一定是2的n次方,所以只有一个1
                        //oldCap例子:0b    10000
                        //hash       0b....11111
                        //hash       0b....01111 	
                        if ((node->data.hash & oldCap) == 0) {
                           //证明高位是0,应该放在低位,也就是01111的情况
                           //如果尾部是null,证明第一次进来,放在头部
                            if (loTail == NULL) {
                                loHead = node;
                            }
                            else {
                                loTail->next = node;
                            }
                            loTail = node;
                        }
                        else {
                            //高位是1,应该放在高位
                            if (hiTail == NULL) {
                                hiHead = node;
                            }
                            else {
                                hiTail->next = node;
                            }
                            hiTail = node;
                        }
                        node = next;
                    }
                    if (loTail != NULL) {
                        //低位有数据
                        loTail->next = NULL;
                        newTab[j].next = loHead;
                        //标志位设置为0证明有数据
                        newTab[j].data.key = 0;
                    }
                    if (hiTail != NULL) {
                        hiTail->next = NULL;
                        //标志位设置为0证明有数据
                        newTab[j + oldCap].next = hiHead;
                        newTab[j + oldCap].data.key = 0;
                    }
                }
            }
        }
        //赋值给hashMap
        hashMap->table = newTab;
        //释放掉旧的hash表
        free(oldTab);
    }
    return newTab;
}

//树的分配
/*
    1. hashmap
    2. table表
    3. table表的下标
    4. 旧的数组
*/
void split(hashNode& node, hashmap& hashmap, hashNode& tab, int index, int bit, int oldCap) {
    hashNode b = node;
    //低位头和尾和高位头和尾
    hashNode loHead = NULL, loTail = NULL;
    hashNode hiHead = NULL, hiTail = NULL;
    //分开后低位的链表(树)和高位的链表(树)
    int lcount = 0;
    int hcount = 0;
    //next:当前节点的下一个
    hashNode e = b, next = NULL;
    for (e; e != NULL; e = next) {
        next = e->next;
        e->next = NULL;
        //应该在低位
        if ((e->data.hash & oldCap) == 0) {
            //第一次进入e的前一个一定是NULL
            e->prev = loTail;
            //e的前一个是空,证明e是头
            if (e->prev == NULL) {
                loHead = e;
            }
            //e不是头
            else {
                loTail->next = e;
            }
            loTail = e;
            lcount++;
        }
        else {
            //应该在高位
            //第一次进入一定是NULL
            e->prev = hiTail;
            //e的前一个是空,证明e是头
            if (e->prev == NULL) {
                hiHead = e;
            }
            //e不是头
            else {
                hiTail->next = e;
            }
            hiTail = e;
            hcount++;
        }
    }
    //到此为止双向链表创建完成了
    //判断低位头有没有空,如果空了,证明所有的结点都到高位去了
    if (loHead == NULL) {
        //设置低位为没有数据
        tab[index].data.key = UN_EXIT;
    }

    //链表赋值完成之后开始下面的树化和去树化操作
    if (loHead != NULL) {
        if (lcount < UNTREEIFY_THRESHOLD) {
            //低位链表数目小于6个,证明可以开始去树化了
            tab[index].next = untreeify(hashmap, loHead);
            tab[index].next->prev = &tab[index];
            tab[index].data.key = 0;
        }
        else {
            //不小于6个,树化
            tab[index].next = loHead;
            tab[index].next->prev = &tab[index];
            tab[index].data.key = 0;
            //如果高位首节点不为空,说明原来的红黑树已经被拆分成两个链表了
            if (hiHead != NULL)
                //开始树化
                treeif(loHead, hashmap->table, loHead->data.hash, hashmap);
        }
    }

    if (hiHead != NULL) {
        if (hcount < UNTREEIFY_THRESHOLD) {
            //低位链表数目小于6个,证明可以开始去树化了
            tab[index + oldCap].next = untreeify(hashmap, hiHead);
            tab[index + oldCap].data.key = 0;
            tab[index + oldCap].next->prev = &tab[index + oldCap];
        }
        else {
            //不小于6个,树化
            tab[index + oldCap].next = hiHead;
            tab[index + oldCap].data.key = 0;
            tab[index + oldCap].next->prev = &tab[index + oldCap];
            //如果低位首节点不为空,说明原来的红黑树已经被拆分成两个链表了
            if (loHead != NULL)
                //开始树化
                treeif(hiHead, hashmap->table, hiHead->data.hash, hashmap);
        }
    }
}

//去树化
hashNode untreeify(hashmap hashMap, hashNode node) {
    //辅助节点
    hashNode hd = NULL, t1 = NULL;
    //p:用于遍历树
    hashNode q = node;
    for (q; q != NULL; q = q->next) {
        //对每一个节点从树节点转化为链表节点,双向链表也去掉
        //获取普通链表节点
        hashNode p = beTreeToNode(q);

        if (t1 == NULL) {
            hd = p;
        }
        else {
            t1->next = p;
        }
        t1 = p;
    }
    return hd;
}

hashNode beTreeToNode(hashNode p){
    return package(p->data.key, p->data.value);
}

//初步树化
hashNode treeifBin(hashNode table, int hash, hashmap hashMap) {
    int length = hashMap->length;
    int index = (length - 1) & hash;
    hashNode e = NULL;
    //数组长度小于64的时候不可以树化
    if (table == NULL || hashMap->size < MIN_TREEIFY_CAPACITY) {
        return resize(hashMap);
    }
    //找到的下标的首个结点不是NULL
    else if ((e = &table[index]) != NULL) {
        //首先把单向链表转化为双向链表
        while (e != NULL && e->next != NULL) {
            e->next->prev = e;
            e = e->next;
        }
        //真正树化
        return treeif(&table[index], table, hash, hashMap);
    }
    return NULL;
}

//红黑树树化,在维护数的同时也要维护双向链表
hashNode treeif(hashNode node ,hashNode table, int hash, hashmap hashMap) {
    //根节点
    hashNode root = NULL;
    //临时结点
    hashNode x = node->next;

    hashNode next = NULL;
    //遍历链表
    for (x; x != NULL; x = next) {
        next = x->next;
        x->lchild = x->rchild = NULL;
        //根结点
        if (root == NULL) {
            //把头设置成root
            root = x;
            root->isRed = BLACK;
        }
        //不是根结点
        else {
            Key key = x->data.key;
            int hash = x->data.hash;
            hashNode temp = root;
            while(1) {
                //根结点的hash
                int tempHash = temp->data.hash;
                //-1. 往左找        1:往右找      0:相等,不会出现,因为key是一定不相等的
                int result = 0;
                //根结点hash>当前结点的hash,往左找位置插入
                if (tempHash > x->data.hash) {
                    result = -1;
                }
                //这里使用hash值作为比较来查找红黑树
                else if (tempHash < x->data.hash) {
                    result = 1;
                }
                else {
                    if (compare(temp->data.key, x->data.key)) {
                        result = -1;
                    }
                    else if (compare(temp->data.key, x->data.key) < 0) {
                        result = 1;
                    }
                    else {
                        result = 0;
                    }
                }
                //记录temp,作为父节点赋值
                hashNode tp = temp;
                temp = result < 0 ? temp->lchild : temp->rchild;
                //查找到叶子结点了
                if (temp == NULL) {
                    x->parent = tp;
                    //判断此时x是在tp的左边还是右边
                    if (result < 0) {
                        tp->lchild = x;
                    }
                    else if (result > 0) {
                        tp->rchild = x;
                    }
                    //插入后要调整平衡
                    insertFixUp(x, root);
                    break;
                }
            }
        }
    }
    //重新对root赋值
    moveRootToFront(table, root, hashMap);
    return table;
}

//重新对root赋值
//确保输入的root作为table的第一个
void moveRootToFront(hashNode& table, hashNode root, hashmap hashMap) {
    int length = 0;
    if (table == NULL || root == NULL) {
        return;
    }
    length = hashMap->length;
    if (table != NULL && root != NULL && length != 0) {
        int index = (length - 1) & root->data.hash;
        //比如11-22-33-44-55-66-77
        //11是first,44是root
        //调用完成之后的结果是:44-11-22-33-55-66-77
        //这里用一个node,不用指针是怕造成死循环44-44-44-44
        hashNode first = table[index].next;
        if (first == root) {
            //不必要调整
            return;
        }
        if (root->next != NULL) {
            root->prev->next = root->next;
            root->next->prev = root->prev;
        }
        root->next = table[index].next;
        table[index].next->prev = root;
        table[index].next = root;
        root->prev = &table[index];
        //检测红黑树的结点是不是规范,如果不是,程序直接结束
        checkInvariants(table[index].next);
    }
}

//检测红黑树是否规范
void checkInvariants(hashNode root) {
    //父节点
    hashNode parent = root->parent;
    //左孩子结点
    hashNode lchild = root->lchild;
    //右孩子结点
    hashNode rchild = root->rchild;
    //前一个
    hashNode prev = root->prev;
    //后一个
    hashNode next = root->next;

    //判断
    //1. 和上一个结点不连接
    if (prev != NULL && prev->next != root) {
        exit(0);
    }
    //2. 和下一个结点没有连起来
    if (next != NULL && next->prev != root) {
        exit(0);
    }
    //3. 和左孩子结点或者右孩子结点没有连起来
    if (parent != NULL && parent->lchild != root && parent->rchild != root) {
        exit(0);
    }
    //4. 左孩子的hash不对
    if (lchild != NULL && (lchild->parent != root || lchild->data.hash > root->data.hash)) {
        exit(0);
    }
    //5. 右孩子的hash不对
    if (rchild != NULL && (rchild->parent != root || rchild->data.hash < root->data.hash)) {
        exit(0);
    }
    //当前结点是红色,孩子结点也是红色
    if (root->isRed && ((lchild != NULL && lchild->isRed) || (rchild != NULL && rchild->isRed))) {
        exit(0);
    }
    //检查左孩子和右孩子
    if (lchild != NULL) {
        checkInvariants(lchild);
    }
    if (rchild != NULL) {
        checkInvariants(rchild);
    }
}

//清空hashMap
void clear(hashmap& hashMap) {
    hashNode node = hashMap->table;
    hashMap->modCount++;
    hashMap->size = 0;
    free(node);
    hashMap->table = NULL;
}

//hashMap是否包含某个key
Status containsKey(Key key, hashmap &hashMap) {
    if (key == UN_EXIT || hashMap == NULL) {
        return ERROR;
    }
    return getNode(hashByKey(key), key, hashMap) == NULL ? ERROR : OK;
}

//hashMap是否包含某个Value
Status containsValue(Value value, hashmap hashMap) {
    hashNode node = hashMap->table;
    if (node != NULL && hashMap->size > 0) {
        for (int i = 0; i < hashMap->length; i++) {
            if (node[i].lchild != NULL || node[i].rchild != NULL) {
                //树的查找
            }
            else if (equals(node[i].data.value, value)) {
                return OK;
            }
            else {
                //调用链表的查找
                hashNode temp = &node[i];
                while (temp != NULL) {
                    if (equals(temp->data.value, value)) {
                        return OK;
                    }
                    temp = temp->next;
                }
            }
        }
    }
    return ERROR;
}

//remove方法,两个,一个通过key删除,一个通过key和value删除
Status removeByKeyValue(Key key, Value value, hashmap& hashMap) {
    if (key == UN_EXIT || value == UN_EXIT || hashMap == NULL || hashMap->table == NULL) {
        return UN_EXIT;
    }
    return removeNode(hashByKey(key), key, value, true, true, hashMap);
}


Status removeByKey(Key key, hashmap& hashMap) {
    if (key == UN_EXIT || hashMap == NULL || hashMap->table == NULL) {
        return UN_EXIT;
    }
    return removeNode(hashByKey(key), key, NULL, false, true, hashMap);
}

//真正的remove方法
Status removeNode(int hash, Key key, Value value, int matchValue, int movable, hashmap& hashMap) {
    hashNode tab = hashMap->table;
    hashNode temp = NULL;
    int length = hashMap->length;
    int index = (length - 1) & hash;
    temp = &(hashMap->table[index]);
    hashNode root = temp;
    //判断条件,看头节点的key判断有没有数据
    if (tab != NULL && length > 0 && temp->data.key != UN_EXIT) {
        temp = temp->next;
        root = temp;
        hashNode node = NULL, e = NULL; 
        Value value1 = NULL;
        //第一个结点就是,但是只有一个结点
        if (temp->data.hash == hash && key != UN_EXIT && equals(temp->data.key, key) && temp->next == NULL) {
            node = temp;
        }
        //是第一个结点,但是有可能是链表
        else if (temp->next != NULL && temp->parent == NULL && temp->lchild == NULL && temp->rchild == NULL) {
            e = temp->next;
            //判断如果是第一个结点的情况
            if (temp == tab[index].next && equals(temp->data.key, key)) {
                tab[index].next = e;
                free(temp);
                return OK;
            }
            //链表的查找
            while (e != NULL) {
                if (e->data.hash == hash && key != UN_EXIT && equals(e->data.key, key)) {
                    node = e;
                    break;
                }
                temp = e;
                e = e->next;    
            }
        }
        //不是链表,有可能是红黑树
        else if (temp->lchild != NULL || temp->rchild != NULL) {
            //红黑树的查找
            node = searchNode(key, temp);
        }

        //判断
        if (node != NULL && (matchValue == 0 || (matchValue == 1 && equals(value1 = node->data.value, value)))) {
            //证明找到了
            if (node->lchild != NULL || node->rchild != NULL || node->parent != NULL) {
                //树的remove
                deleteNode(hashMap, node->data.hash, node->data.key, node->data.value, root, node);
            }
            //链表的情况:中间或者队尾
            else if (node->next != NULL || (node->next == NULL && tab[index].next != node)) {
                //链表
                temp->next = node->next;
                free(node);
            }
            //只有一个结点
            else if(node == tab[index].next && node->next == NULL){
                tab[index].next = node->next;
                tab[index].data.key = UN_EXIT;
                free(node);
            }
            hashMap->modCount++;
            hashMap->size--;
            return OK;
        }
        return ERROR;
    }
    else {
        return ERROR;
    }
}

//replace方法
//根据key和value来进行匹配
Status replaceByKeyValue(Key key, Value oldValue, Value newValue, hashmap& hashMap) {
    hashNode e = NULL;
    e = getNode(hashByKey(key), key, hashMap);
    if (e != NULL && equals(e->data.value,oldValue)) {
        e->data.value = newValue;
        return OK;
    }
    return FALSE;
}

//根据key来进行匹配
Status replaceByKey(Key key, Value newValue, hashmap& hashMap) {
    hashNode e = NULL;
    e = getNode(hashByKey(key), key, hashMap);
    if (e != NULL) {
        e->data.value = newValue;
        return OK;
    }
    return FALSE;
}

//初始化
void initByOther(HashNode& node1, hashNode& node2) {
    node1.data = node2->data;
    node1.isRed = node2->isRed;
    node1.lchild = node2->lchild;
    node1.next = node2->next;
    node1.rchild = node2->rchild;
    node1.parent = node2->parent;
    node1.prev = node2->prev;
}

void meun() {
    printf("********a. 初始化(默认)				        b. 初始化(自定义阈值)\n");
    printf("********c. 初始化(自定义阈值和负载因子)			d. 加入结点(可以进行替换)\n");
    printf("********e. 加入结点(不可进行替换)				f. 查找是否包含key\n");
    printf("********g. 菜单	 	                                        h. 打印	\n");
    printf("********i. 根据key替换                 		        	j. 查找key对应得value\n");
    printf("********k. 根据key和value替换                 	                l. 根据key移除结点\n");
    printf("********m. 根据key和value移除结点\n");
}

//对链表进行清除
void clear(hashNode table) {
    while (table != NULL) {
        hashNode temp = table;
        table = table->next;
        free(temp);
    }
}







6、RBTree.cpp:实现红黑树的一些操作

#include "RBTree.h"


//方法
hashNode parentOf(hashNode node) {
	//一个树结点
	if (node != NULL &&  node->parent != NULL) {
		return node->parent;
	}
	return NULL;
}

/**
     * 结点是否为红色
*/
int RedOrNot(hashNode node) {
    if (node != NULL) {
        return node->isRed == RED;
    }
    return false;
}

/**
     * 结点是否为黑色
*/
int isBlack(hashNode node) {
    if (node != NULL) {
        return node->isRed == BLACK;
    }
    return false;
}

/**
     * 中序打印
*/
void inOrderPrint(hashNode root) {
    inOrderPrint_1(root);
}

/**
 * 中序打印二叉树
 */
void inOrderPrint_1(hashNode root) {
    if (root != NULL) {
        inOrderPrint(root->lchild);
        printf("key: %d -> value: %d", root->data.key, root->data.value);
        inOrderPrint(root->rchild);
    }
}

hashNode getRoot(hashNode root) {
    hashNode node = root, p = NULL;
    for ( ; ; ) {
        p = root->parent;
        if (p == NULL) {
            return root;
        }
        else {
            root = p;
        }
    }
}

/*
            左旋
             B                   D 
            /  \                / \
           A    D   ->         B   E  
               / \           /  \
              C   E         A    C


*/
void leftRotate(hashNode& root, hashNode x) {
    //假设x是B,y是D
    hashNode y = x->rchild;
    //1. 将y的左子节点的父节点更新为x,让C的父节点设置为B
    x->rchild = y->lchild;
    if (y->lchild != NULL) {
        y->lchild->parent = x;
    }

    //2. 当x的父节点不为空,更新y的父节点为x的父节点,并将x的父节点指定子树指定为y
    if (x->parent != NULL) {
        y->parent = x->parent;
        if (x == x->parent->lchild) {
            //x是左节点
            x->parent->lchild = y;
        }
        else {
            //x的父节点为空,也就是说x是根节点,此时需要更新y结点
            //x是右节点
            x->parent->rchild = y;
        }
    }
    else {
        //x的父节点为空,也就是说x是根节点,此时需要更新y结点为根结点
        root = y;
        y->parent = NULL;
    }

    //将x的父节点更新为y,将y的左子结点更新为x
    x->parent = y;
    y->lchild = x;
}

/*
            右旋
            C             A
           / \           / \
          A   E ->      B   C
         / \               / \
        B   D             D   E
*/
void rightRotate(hashNode& root, hashNode y) {
    //y=C, x=A
    hashNode x = y->lchild;
    //1. 将y的左子节点指向x的右子结点,并且更新x的右子节点的父节点为y
    y->lchild = x->rchild;
    if (x->rchild != NULL) {
        x->rchild->parent = y;
    }
    //2. 当y的父节点不为空。更新x的父节点为y的父节点,y的父节点指定子节点(y当前位置)为x
    if (y->parent != NULL) {
        x->parent = y->parent;
        if (y->parent->lchild == y) {
            y->parent->lchild = x;
        }
        else {
            y->parent->rchild = x;
        }
    }
    else {
        root = x;
        root->parent = NULL;
    }
    //3. 更新y的父节点为x,更新x的右子结点为y
    y->parent = x;
    x->rchild = y;
}

/**
    * 公开的插入方法
    * @param key
    * @param value
    */
void insert(Key key, Value value, hashNode& root, hashmap& hashMap) {
    hashNode node = package(key, value);
    insertReal(node, root, hashMap);
}

void insertReal(hashNode node, hashNode& root, hashmap& hashMap) {
    hashNode parent = NULL;
    hashNode x = root;
    while (x != NULL) {
        parent = x;
        //cmp>0,说明node的key大于x的key,到右子树查找
        //cmp=0,说明node的key等于x的key,进行替换
        //cmp<0,说明node的key小于x的key,需要到x的左子树查找
        int cmp = compare(node->data.hash, x->data.hash);
        if (cmp > 0) {
            //往右找
            x = x->rchild;
        }
        else if(cmp == 0) {
            //替换
            x->data.value = node->data.value;
            return;
        }
        else {
            //往左找
            x = x->lchild;
        }
    }
    //这一步找到了x为null
    node->parent = parent;
    //判断node和parent的key谁大
    if (parent != NULL) {
        int cmp = compare(node->data.key, parent->data.key);
        if (cmp > 0) {
            //当前node的key比parent的key大,需要把node放入parent的右子结点
            parent->rchild = node;
        }
        else if(cmp < 0){
            //当前node的key比parent的key小,需要把node放入parent的左子结点
            parent->rchild = node;
        }
    }
    else {
        //第一次插入,根是空的
        root = node;
    }
    //调整双向链表的位置
    node->next = parent->next;
    if (parent->next != NULL) {
        parent->next->prev = node;
    }
    parent->next = node;
    node->prev = parent;

    //有可能不平衡,修复红黑树
    insertFixUp(node, root);

    //调整树的根部
    moveRootToFront(hashMap->table, root, hashMap);
}



/**
     * 修复红黑树
     * 1. 红黑树为空树,将根结点染色为黑色
     * 2. 插入结点的key已经存在,不需要存在
     * 3. 插入的父节点为黑色,因为所插入的路径黑色结点数目不变,所以不需要处理
     *
     * 4. 需要我们去处理,插入的结点的父节点为红色
     *    4.1 叔叔结点存在,并且为红色(父-叔 双红),将爸爸和叔叔染色为黑色。将爷爷染色为红色
     *        并且以爷爷结点为当前结点进行下一轮处理
     *    4.2 叔叔节点不存在或者为黑色,父节点为爷爷结点的左子树
     *        4.2.1 插入的结点为其父节点的左子节点(LL), 将爸爸染色为黑色,然后将爷爷染色为红色,
     *              然后以爷爷结点右旋
     *        4.2.2 插入的结点为其父节点的左子节点(LR), 以爸爸结点进行一次左旋得到LL双红的情况,
     *              然后指定爸爸结点为当前结点进行下一轮处理(4.2.1)
     *    4.3 叔叔节点不存在或者为黑色,父节点为爷爷结点的右子树
     *        4.3.1 插入的结点为其父节点的右子节点(RR), 将爸爸染色为黑色,然后将爷爷染色为红色,
     *              然后以爷爷结点左旋
     *        4.3.2 插入的结点为其父节点的左子节点(RL), 以爸爸结点进行一次右旋得到RR双红的情况,
     *              然后指定爸爸结点为当前结点进行下一轮处理(4.3.1)
     *
     */
void insertFixUp(hashNode& node, hashNode&  root) {
    //确保根节点是黑色的,第一次插入内
    hashNode temp = node;
    hashNode parent = parentOf(node);
    hashNode grandParent = parentOf(parent);

    //判断根结点并赋值为BLACK
    //1. 自身是根结点
    if (temp != NULL && temp->parent == NULL) {
        temp->isRed = BLACK;
    }
    //2. 父节点是根结点
    if (parent != NULL && parent->parent == NULL) {
        parent->isRed = BLACK;
    }
    //祖父结点是根结点
    if (grandParent != NULL && grandParent->parent == NULL) {
        grandParent->isRed = BLACK;
    }

    //情景1.2.3,我们都不需要调整
    //情景4:插入结点父节点为红色
     if (parent != NULL && RedOrNot(parent)) {
        hashNode uncle = NULL;
        //父节点为爷爷结点的左子结点
        if (parent == grandParent->lchild) {
            uncle = grandParent->rchild;
            //4.1 叔叔结点存在,并且为红色(父-叔 双红)
            if (uncle != NULL && RedOrNot(uncle)) {
                //将爸爸和叔叔染色为黑色。将爷爷染色为红色,并且以爷爷结点为当前结点进行下一轮处理
                parent->isRed = BLACK;
                uncle->isRed = BLACK;
                grandParent->isRed = RED;
                insertFixUp(grandParent, root);
                return;
            }
            //4.2 叔叔节点不存在或者为黑色
            if (uncle == NULL || isBlack(uncle)) {
                //4.2.1插入的结点为其父节点的左子节点(LL)
                if (node == parent->lchild) {
                    parent->isRed = BLACK;
                    grandParent->isRed = RED;
                    rightRotate(root, grandParent);
                    return;
                }
                else {
                    //4.2.2 插入的结点为其父节点的左子节点(LR)
                    if (node == parent->rchild) {
                        leftRotate(root, parent);
                        insertFixUp(parent, root);
                        return;
                    }
                }
            }
        }
        else {
            //父节点为爷爷结点的右子树
            uncle = grandParent->lchild;
            //4.1 叔叔结点存在,并且为红色(父-叔 双红)
            if (uncle != NULL && RedOrNot(uncle)) {
                //将爸爸和叔叔染色为黑色。将爷爷染色为红色,并且以爷爷结点为当前结点进行下一轮处理
                parent->isRed = BLACK;
                uncle->isRed = BLACK;
                grandParent->isRed = RED;
                insertFixUp(grandParent, root);
                return;
            }
            //4.3 叔叔节点不存在或者为黑色,父节点为爷爷结点的右子树
            if (uncle == NULL || isBlack(uncle)) {
                //4.3.1 插入的结点为其父节点的右子节点(RR)
                if (node == parent->rchild) {
                    parent->isRed = BLACK;
                    grandParent->isRed = RED;
                    leftRotate(root, grandParent);
                    return;
                }

                //4.3.2插入的结点为其父节点的左子节点(RL)
                if (node == parent->lchild) {
                    rightRotate(root, parent);
                    insertFixUp(parent, root);
                    return;
                }
            }
        }
       
    }
}

//删除叶子结点
void deleteNode(hashmap& hashmap, int hash, Key key, Value value, hashNode& root, hashNode node) {
    if (hashmap == NULL || hashmap->table == NULL || hashmap->length == 0) {
        return;
    }
    //获取下标
    int index = (hashmap->length - 1) & hash;
    hashNode table = hashmap->table;
    //首个节点
    hashNode first = table[index].next;
    hashNode realRoot = first;
    //succ-调用这个方法的节点(待删除节点)的后驱节点
    hashNode succ = node->next;
    //prev - 调用这个方法的节点(待删除节点)的前驱节点
    hashNode pred = node->prev;
    /**
    * 维护双向链表(map在红黑树数据存储的过程中,除了维护红黑树之外还对双向链表进行了维护)
    * 从链表中将该节点删除
    * 如果前驱节点为空,说明删除节点是头节点,删除之后,头节点直接指向了删除节点的后继节点
    */
    if (pred->data.value == UN_EXIT) {
        table[index].next = first = succ;
    }
    else {
        //删除的不是头节点
        pred->next = succ;
    }
    if (succ != NULL) {
        succ->prev = pred;
    }
    // 如果头节点(即根节点)为空,说明该节点删除后,红黑树为空,直接返回
    if (first == NULL) {
        return;
    }
    // 如果父节点不为空,说明删除后,调用root方法重新获取当前树的根节点
    if (first->parent != NULL) {
        realRoot = getRoot(first);
    }
    /**
    * 当以下三个条件任一满足时,当满足红黑树条件时,说明该位置元素的长度少于6(UNTREEIFY_THRESHOLD),需要对该位置元素链表化
    * 1、root == NULL:根节点为空,树节点数量为0
    * 2、root.rchild == NULL:右孩子为空,树节点数量最多为2
    * 3、(rl = root.left) == null || rl.left == null):
    *      (rl = root.left) == null:左孩子为空,树节点数最多为2
    *      rl.left == null:左孩子的左孩子为NULL,树节点数最多为6
    */
    if (hashmap->size <= UNTREEIFY_THRESHOLD) {
        table[index].next = untreeify(hashmap, first);
        hashmap->table = table;
        return;
    }
    hashNode var = package(key, value);
    //否则还是树,调用树的删除
    deleteNodeReal(var, root, hashmap);
    //重新赋值table
    hashmap->table = table;
    //重新赋值根节点
    if (root->parent != NULL) {
        root = realRoot;
    }
}
//真正的删除
void deleteNodeReal(hashNode node, hashNode& root, hashmap& hashMap) {
    hashNode x = NULL;  // x 指向 y 的唯一子节点或指向 NULL
    hashNode z = searchNode(node->data.key, root);
    hashNode parent = NULL;
    hashNode y = z; //y 为从树中删除的节点或者移至树内的节点
    int y_color = -1;   //保存y的颜色
    if (z == NULL) {
        //没找到
        return;
    }
    //y的颜色
    y_color = y->isRed;
    if (z->lchild == NULL) {
        //情况1:被删除的z左节点是空,右孩子无限制,使用右孩子替换
        x = z->rchild;
        //使用z的右孩子替换
        transplate(z, z->rchild, root);
        parent = z->parent;
    }
    else if (z->rchild == NULL) {
        //情况2:右孩子为空,使用左孩子替换
        x = z->lchild;
        //使用z的右孩子替换
        transplate(z, z->lchild , root);
        parent = z->parent;
    }
    else {
        //z有两个结点
        /*
        ①、找到结点D的后继结点S

        ②、将结点S的key值赋给结点D;

        ③、再将结点S从树中删除,并用结点S的右孩子替代结点S的位置;[注:从前面的描述可以看出,其实被删的是结点D的后继结点S]

        ④、如果被删结点S为红色,则红黑树性质未被破坏,因此不需做其他调整;

        ⑤、如果被删结点S为黑色,则需进一步做调整处理。
        */

        //y是找到的后继结点,y的左孩子一定是NULL
        y = searchMin(z->rchild);
        //记录被删除的颜色
        y_color = y->isRed;
        x = y->rchild;
        if (y->parent == z) {
            //z的后继节点是y,证明y是z的右孩子结点,并且y没有左孩子结点
            if (x == NULL) {
                y->parent->rchild = NULL;
            }
            else {
                x->parent = y;
            }
            //y取代z
            transplate(z, y, root);
            y->lchild = z->lchild;
            y->lchild->parent = y;
            y->isRed = z->isRed;
            //这里的parent是因为直接取到z的孩子结点
            parent = y;
        }
        else {
            //y取代z
            hashNode yRchild = y->rchild;
            parent = y->parent;
            //如果右结点为null,那么直接赋值
            if (yRchild == NULL) {
                y->parent->lchild = NULL;
            }
            else {
                //否则就替换2次
                transplate(y, yRchild, root);
            }
            transplate(z, y, root);
            //y结点要替换到z结点的位置,赋值右子树
            y->lchild = z->lchild;
            y->lchild->parent = y;
            y->isRed = z->isRed;
            y->rchild = z->rchild;
            y->rchild->parent = y;
        }
    }
    //判断如果删除的结点是黑结点,进行修复
    //对x进行修复,因为x是填充到y位置的
    if (y_color == BLACK) {
        deleteFixUp(x, parent, root);
    }
    //删除之后要调整头部
    moveRootToFront(hashMap->table, root, hashMap);
    //释放删除的结点z
    free(z);
    z = NULL;
    return;
}

//删除修复
//如果删除的结点时红色结点,不用调整平衡,如果删除的结点时黑节点,就要调整
/*
        前提1:参照结点N为父结点P的左孩子
            情况1:参照结点N的兄弟B是红色的
            处理过程:
                ①、将父结点P的颜色改为红色,兄弟结点的颜色改为黑色;
                ②、以父结点P为支点进行左旋处理;
                ③、情况1转变为情况2或3、4,后续需要依次判断处理。

            情况2:参照结点N的兄弟B是黑色的,且B的两个孩子都是黑色的
            处理过程:
                ①、如果parent此时为红,则把brother的黑色转移到parent上
                ②、如果此时parent为黑,即此时全黑了,则把brother涂红,导致brother分支少一个黑,使整个分支都少了一个黑,需要对parent又进行一轮调整

            情况3:参照结点N的兄弟B是黑色的,且B的左孩子是红色的,右孩子是黑色的
            处理过程:
                ①、将兄弟结点的左孩子调整为父颜色,父颜色调整为黑色
                ②、以兄弟结点开始右旋
                ③、以父节点左旋

            情况4:参照结点N的兄弟B是黑色的,且B的左孩子是黑色的,右孩子是红色的
            处理过程:
                ①、将父结点P的颜色拷贝给兄弟结点B,再将父结点P和兄弟结点的右孩子BR的颜色改为黑色;
                ②、以父结点P为支点,进行左旋处理;
                ③、将该结点改为树的根结点,也意味着调整结束。


         前提2:参照结点N为父结点P的右孩子
            情况5:参照结点N的兄弟B是红色的
            处理过程:
                ①、将父结点P的颜色改为红色,兄弟结点的颜色改为黑色;
                ②、以父结点P为支点进行右旋处理;
                ③、情况5转变为情况6或7、8,后续需要依次判断处理。   

            情况6:参照结点N的兄弟B是黑色的,且B的两个孩子都是黑色的
            处理过程:
                ①、如果parent此时为红,则把brother的黑色转移到parent上
                ②、如果此时parent为黑,即此时全黑了,则把brother涂红,导致brother分支少一个黑,使整个分支都少了一个黑,需要对parent又进行一轮调整

            情况7:参照结点N的兄弟B是黑色的,且B的右孩子是红色的,左孩子是黑色的
            处理过程:
                ①、将兄弟结点的右孩子调整为父颜色,父颜色调整为黑色
                ②、以兄弟结点开始左旋
                ③、以父节点右旋

            情况8:参照结点N的兄弟B是黑色的,且B的右孩子是黑色的,左孩子是红色的
            处理过程:
                ①、将父结点P的颜色拷贝给兄弟结点B,再将父结点P和兄弟结点的右孩子BR的颜色改为黑色;
                ②、以父结点P为支点,进行右旋处理;
                ③、将该结点改为树的根结点,也意味着调整结束。
*/
void deleteFixUp(hashNode x, hashNode parent, hashNode& root) {
    hashNode brother = NULL;
    //如果要修复的树是根,由于没有兄弟姐弟啊,那么把x的颜色改成黑色就好了
    while ((x == NULL || x->isRed == BLACK) && x != root) {
        // 前提1:参照结点x为父结点P的左孩子
        hashNode p = parent;
        if (x == p->lchild) {
            //兄弟是右结点
            brother = p->rchild;
            //情况1:参照结点N的兄弟B是红色的
            /*
                ①、将父结点P的颜色改为红色,兄弟结点的颜色改为黑色;
                ②、以父结点P为支点进行左旋处理;
                ③、情况1转变为情况2或3、4,后续需要依次判断处理。
            */
            if (brother != NULL && brother->isRed == RED) {
                brother->isRed = BLACK;
                p->isRed = RED;
                //以父节点左旋
                leftRotate(root, p);
                //完成之后兄弟要重新更新进行下一步操作
                brother = p->rchild;
            }
            // 情况2:参照结点N的兄弟B是黑色的,且B的两个孩子都是黑色的
            /*
                ①、将兄弟结点B的颜色改为红色
                ②、情况2处理完成后,不必再进行情况3、4的判断,但需重新循环判断前提1、2。
            */
            if (brother != NULL && brother->isRed == BLACK && (brother->lchild == NULL || isBlack(brother->lchild)) && (brother->rchild == NULL || isBlack(brother->rchild))) {
                brother->isRed = RED;
                // 如果parent此时为红,则把brother的黑色转移到parent上
                if (p->isRed = RED) {
                    p->isRed = BLACK;
                    brother->isRed = RED;
                    break;
                }
                else {
                    // 如果此时parent为黑,即此时全黑了,则把brother涂红,导致brother分支少一个黑,使整个分支都少了一个黑,需要对parent又进行一轮调整
                    brother->isRed = RED;
                    x = parent;
                    parent = x->parent;
                }

                
            }
            else {
                // 情况3:参照结点N的兄弟B是黑色的,且B的左孩子是红色的
            /*
                ①、将兄弟结点的左孩子调整为父颜色,父颜色调整为黑色
                ②、以兄弟结点开始右旋
                ③、以父节点左旋
            */
                if (brother != NULL && brother->isRed == BLACK && RedOrNot(brother->lchild)) {
                    brother->lchild->isRed = p->isRed;
                    p->isRed = BLACK;
                    rightRotate(root, brother);
                    leftRotate(root, parent);
                }
                //情况4:参照结点N的兄弟B是黑色的,且B的左孩子是黑色的,右孩子是红色的
                /*
                    ①、将父结点P的颜色拷贝给兄弟结点B,再将父结点P和兄弟结点的右孩子BR的颜色改为黑色;
                    ②、以父结点P为支点,进行左旋处理;
                    ③、将该结点改为树的根结点,也意味着调整结束。

                */
                else if (brother != NULL && brother->isRed == BLACK && RedOrNot(brother->rchild)) {
                    brother->isRed = p->isRed;
                    p->isRed = BLACK;
                    brother->rchild->isRed = BLACK;
                    leftRotate(root, p);
                }
                break;
            }
        

        }

        // 前提2:参照结点x为父结点P的左孩子
        else {
            //兄弟是左结点
            brother = p->lchild;
            //情况5:参照结点N的兄弟B是红色的
            /*
                ①、将父结点P的颜色改为红色,兄弟结点的颜色改为黑色;
                ②、以父结点P为支点进行右旋处理;
                ③、情况5转变为情况6或7、8,后续需要依次判断处理。  
            */
            if (brother->isRed == RED) {
                p->isRed = RED;
                brother->isRed = BLACK;
                rightRotate(root, p);
                brother = p ->lchild;
            }

            //情况6:参照结点N的兄弟B是黑色的,且B的两个孩子都是黑色的
            /*
                ①、将兄弟结点B的颜色改为红色;
                ②、情况6处理完成后,不必再进行情况7、8的判断,但需要重新循环判断前提1、2。
            */
            if ((brother->lchild == NULL || brother->lchild->isRed == BLACK)
                && (brother->rchild == NULL || brother->rchild->isRed == BLACK)) {
                // 如果parent此时为红,则把brother的黑色转移到parent上
                if (p->isRed == RED) {
                    p->isRed = BLACK;
                    brother->isRed = RED;
                    break;
                }
                // 如果此时parent为黑,即此时全黑了,则把brother涂红,导致brother分支少一个黑,使整个分支都少了一个黑,需要对parent又进行一轮调整
                else {
                    brother->isRed = RED;
                    x = parent;
                    parent = x->parent;
                }
            }
            else {
                //左右孩子必有一个是红色
                    // 情况7:参照结点N的兄弟B是黑色的,且B的右孩子是红色的
                    /*
                        ①、将兄弟结点的右孩子调整为父颜色,父颜色调整为黑色
                        ②、以兄弟结点开始左旋
                        ③、以父节点右旋
                    */
                if (brother->isRed == BLACK && brother->rchild != NULL && brother->rchild->isRed == RED) {
                    brother->rchild->isRed = p->isRed;
                    p->isRed = BLACK;
                    leftRotate(root, brother);
                    rightRotate(root, p);

                }

                   
             //左右孩子必有一个是红色
                    // 情况8:参照结点N的兄弟B是黑色的,且B的左孩子是红色的
                    /*
                     ①、将父结点P的颜色拷贝给兄弟结点B,再将父结点P和兄弟结点的右孩子BR的颜色改为黑色;
                    ②、以父结点P为支点,进行右旋处理;
                    ③、将该结点改为树的根结点,也意味着调整结束。
                    */
                else if (brother != NULL && brother->isRed == BLACK && brother->lchild != NULL && RedOrNot(brother->lchild)) {
                    brother->isRed = p->isRed;
                    p->isRed = BLACK;
                    brother->lchild->isRed = BLACK;
                    //以父节点进行旋转
                    rightRotate(root, p);
                }
            }

        }
    }
    //修改x颜色为黑色
    if (x != NULL) {
        x->isRed = BLACK;
    }

    return;
}

//1. 子树替换
//v代替u
void transplate(hashNode u, hashNode v, hashNode& root) {

    if (u->parent == NULL) {
        root = v;
    }
    else if (u == u->parent->lchild) {
        //左孩子
        u->parent->lchild = v;
    }
    else {
        //右孩子
        u->parent->rchild = v;
    }
    if (v != NULL) {
        v->parent = u->parent;
    }

}

//2.查找元素
hashNode searchNode(Value key, hashNode root) {
    hashNode node = NULL;
    if (key == NULL || root == NULL) {
        return NULL;
    }
    if ((root->data.hash == hashByKey(key)) && (equals(root->data.key, key) == OK)) {
        return root;
    }
    if ((node = searchNode(key, root->lchild)) != NULL) {
        return node;
    }
    return searchNode(key, root->rchild);
}


/* 最小关键字元素 */
hashNode searchMin(hashNode root){
    hashNode temp = root;
    while (temp != NULL && temp->lchild != NULL) {
        temp = temp->lchild;
    }
    return temp;
}

/*****************************************************************************
* @brief  水平画树
* @param  node	二叉树节点
* @param  left	判断左右
* @param  str 	可变字符串
*****************************************************************************/
void draw_level(hashNode node, bool left, char* str) {
    if (node->rchild) {
        draw_level(node->rchild, false, strcat(str, (left ? "|     " : "      ")));
    }
    printf("\t\t\t");
    printf("%s", str);
    //printf("\t\t");
    printf("%c", (left ? '\\' : '/'));
    printf("-----");
    printf("(%d:%d)%c\n", node->data.key, node->data.value, node->isRed ? 'R' : 'B');



    if (node->lchild) {
        draw_level(node->lchild, true, strcat(str, (left ? "      " : "|     ")));
    }
    //  "      " : "|     " 长度为 6
    str[strlen(str) - 6] = '\0';
}

/*****************************************************************************
* @brief  根节点画树
* @param  root	二叉树根节点
*****************************************************************************/
void draw(hashNode root) {
    char str[STR_MAX_SIZE];
    memset(str, '\0', STR_MAX_SIZE);

    /**
     * 1. 在 windows 下,下面是可执行的
     * 2. 在 Linux   下,执行会报 Segmentation fault
     *      需要使用中间变量
     */
    if (root->rchild) {
        draw_level(root->rchild, false, str);
    }
    printf("\t\t\t");
    printf("(%d:%d)%c\n", root->data.key, root->data.value, root->isRed?'R':'B');
    if (root->lchild) {
        draw_level(root->lchild, true, str);
    }
}

//链表打印
void drawLine(hashNode root) {
    while (root != NULL) {
        printf("(%d:%d)", root->data.key, root->data.value);
        root = root->next;
        if (root != NULL) {
            printf("------>");
        }
    }
    
}

//总的打印
void print(hashNode table, hashmap hashMap) {
    hashNode temp = table;
    int count = 0;
    //移动
    printf("\n\n\n\n");
    printf("\t\t");
    //遍历table一个一个打印
    for (int i = 0; i < hashMap->length; i++) {
        printf("[下标%d] --> ", i);
        if (table[i].data.key != UN_EXIT && (table[i].next->lchild != NULL || table[i].next->rchild != NULL || table[i].next->parent != NULL)) {
            printf("\n\n\n\n");
            draw(table[i].next);
        }
        else if(table[i].data.key != UN_EXIT){
            
            drawLine(table[i].next);
        }
        printf("\n\n\n\n");
        printf("\t\t");
    } 
    printf("\n");
}






如有错误,欢迎指出

============================================
2023.5.8更新,插入节点比较多的时候会异常,是扩容的时候某些下标没初始化(或者有些地方free了),但是具体在哪出问题还没有仔细测过

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值