Merge branch 'prepare_for_master' of https://git.trustie.net/xuos/xiuos into prepare_for_master
| 
						 | 
				
			
			@ -240,5 +240,9 @@ menu "test app"
 | 
			
		|||
                bool "Config test soft timer"
 | 
			
		||||
                default n
 | 
			
		||||
            
 | 
			
		||||
            menuconfig USER_TEST_RBTREE
 | 
			
		||||
                bool "Config test red black tree"
 | 
			
		||||
                default n
 | 
			
		||||
 | 
			
		||||
        endif
 | 
			
		||||
endmenu
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,5 +101,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
 | 
			
		|||
        SRC_FILES += test_timer.c
 | 
			
		||||
    endif
 | 
			
		||||
 | 
			
		||||
    ifeq ($(CONFIG_USER_TEST_RBTREE),y)
 | 
			
		||||
        SRC_FILES += test_rbtree/test_rbtree.c
 | 
			
		||||
    endif    
 | 
			
		||||
 | 
			
		||||
    include $(KERNEL_ROOT)/compiler.mk
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 After Width: | Height: | Size: 75 KiB  | 
| 
		 After Width: | Height: | Size: 102 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
# 基于cortex-m3-emulator实现哈希表并测试验证##
 | 
			
		||||
 | 
			
		||||
## 1. 简介
 | 
			
		||||
利用c语言实现了哈希表(HashMap),包括添加键值对(Put),获取键对应的值(Get), 删除健(Delete),清空哈希表(Clear), 迭代遍历哈希表(hashMapIterator)等功能
 | 
			
		||||
操作。
 | 
			
		||||
 | 
			
		||||
利用数组(Entry)作为存储空间,利用链表(*next)解决冲突。当哈希表的大小超过数组大小后,为避免发生冲突过多的情况,可以对哈希表扩容。
 | 
			
		||||
 | 
			
		||||
## 2. 数据结构设计说明
 | 
			
		||||
键值对结构
 | 
			
		||||
typedef struct entry {
 | 
			
		||||
    void * key;             // 键
 | 
			
		||||
    void * value;           // 值
 | 
			
		||||
    struct entry * next;    // 冲突链表
 | 
			
		||||
}*Entry;
 | 
			
		||||
 | 
			
		||||
哈希结构
 | 
			
		||||
typedef struct hashMap {
 | 
			
		||||
    int size;           // 当前大小
 | 
			
		||||
    int listSize;       // 有效空间大小
 | 
			
		||||
    HashCode hashCode;  // 哈希函数
 | 
			
		||||
    Equal equal;        // 判等函数
 | 
			
		||||
    Entry list;         // 存储区域
 | 
			
		||||
    Put put;            // 添加键的函数
 | 
			
		||||
    Get get;            // 获取键对应值的函数
 | 
			
		||||
    Remove remove;      // 删除键
 | 
			
		||||
    Clear clear;        // 清空Map
 | 
			
		||||
    Exists exists;      // 判断键是否存在
 | 
			
		||||
    Boolean autoAssign;	// 设定是否根据当前数据量动态调整内存大小,默认开启
 | 
			
		||||
}*HashMap;
 | 
			
		||||
 | 
			
		||||
包括以下函数功能,分别为:
 | 
			
		||||
`createHashMap`:创建一个哈希结构
 | 
			
		||||
`defaultPut`:添加键值对
 | 
			
		||||
`defaultGet`:获取键对应值
 | 
			
		||||
`defaultRemove`:删除指定键的键值对
 | 
			
		||||
`defaultExists`:判断键值是否存在
 | 
			
		||||
`defaultClear`:清空Map的函数类型
 | 
			
		||||
`resetHashMap`:重新构建哈希表
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 3. 测试程序说明
 | 
			
		||||
测试了哈希表的插入键值对(Put),判断键是否存在(Exist),获取键对应的值(Get), 删除健(Delete),迭代遍历哈希表(hashMapIterator),清空哈希表(Clear)等操作。
 | 
			
		||||
并展示了利用链地址法解决哈希冲突的示例, 两个不同的人(Bob和Li Ming)的hashcode相同。
 | 
			
		||||
 | 
			
		||||
## 4. 运行结果(##需结合运行测试截图按步骤说明##)
 | 
			
		||||

 | 
			
		||||
打开menuconfig之后,将test_hash_map开启(y),保存后退出
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
编译XiZi-cortex-m3-emulator.elf成功
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
启动qemu模拟Xiuos操作系统,验证TestHash注册Shell命令
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
执行TestHash命令,打印测试结果。
 | 
			
		||||
 | 
			
		||||
| 
		 After Width: | Height: | Size: 94 KiB  | 
| 
		 After Width: | Height: | Size: 95 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,323 @@
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
* @file:    test_hash.c
 | 
			
		||||
* @brief:   a application of test hash function
 | 
			
		||||
* @version: 3.0
 | 
			
		||||
* @author:  Yao wenying
 | 
			
		||||
* @date:    2023/05/26
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <transform.h>
 | 
			
		||||
#include"test_hash.h"
 | 
			
		||||
 | 
			
		||||
int defaultHashCode(HashMap hashMap, let key) {
 | 
			
		||||
	char * k = (char *)key;
 | 
			
		||||
	unsigned long h = 0;
 | 
			
		||||
	while (*k) {
 | 
			
		||||
		h = (h << 4) + *k++;
 | 
			
		||||
		unsigned long g = h & 0xF0000000L;
 | 
			
		||||
		if (g) {
 | 
			
		||||
			h ^= g >> 24;
 | 
			
		||||
		}
 | 
			
		||||
		h &= ~g;
 | 
			
		||||
	}
 | 
			
		||||
	return h % hashMap->listSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Boolean defaultEqual(let key1, let key2) {
 | 
			
		||||
	return strcmp((string)key1, (string)key2) ? False : True;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void resetHashMap(HashMap hashMap, int listSize) {
 | 
			
		||||
 | 
			
		||||
	if (listSize < 8) return;
 | 
			
		||||
 | 
			
		||||
	// 键值对临时存储空间
 | 
			
		||||
	Entry tempList = newEntryList(hashMap->size);
 | 
			
		||||
 | 
			
		||||
	HashMapIterator iterator = createHashMapIterator(hashMap);
 | 
			
		||||
	int length = hashMap->size;
 | 
			
		||||
	for (int index = 0; hasNextHashMapIterator(iterator); index++) {
 | 
			
		||||
		// 迭代取出所有键值对
 | 
			
		||||
		iterator = nextHashMapIterator(iterator);
 | 
			
		||||
		tempList[index].key = iterator->entry->key;
 | 
			
		||||
		tempList[index].value = iterator->entry->value;
 | 
			
		||||
		tempList[index].next = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	freeHashMapIterator(&iterator);
 | 
			
		||||
 | 
			
		||||
	// 清除原有键值对数据
 | 
			
		||||
	hashMap->size = 0;
 | 
			
		||||
	for (int i = 0; i < hashMap->listSize; i++) {
 | 
			
		||||
		Entry current = &hashMap->list[i];
 | 
			
		||||
		current->key = NULL;
 | 
			
		||||
		current->value = NULL;
 | 
			
		||||
		if (current->next != NULL) {
 | 
			
		||||
			while (current->next != NULL) {
 | 
			
		||||
				Entry temp = current->next->next;
 | 
			
		||||
				free(current->next);
 | 
			
		||||
				current->next = temp;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 更改内存大小
 | 
			
		||||
	hashMap->listSize = listSize;
 | 
			
		||||
	Entry relist = (Entry)realloc(hashMap->list, hashMap->listSize * sizeof(struct entry));
 | 
			
		||||
	if (relist != NULL) {
 | 
			
		||||
		hashMap->list = relist;
 | 
			
		||||
		relist = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 初始化数据
 | 
			
		||||
	for (int i = 0; i < hashMap->listSize; i++) {
 | 
			
		||||
		hashMap->list[i].key = NULL;
 | 
			
		||||
		hashMap->list[i].value = NULL;
 | 
			
		||||
		hashMap->list[i].next = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 将所有键值对重新写入内存
 | 
			
		||||
	for (int i = 0; i < length; i++) {
 | 
			
		||||
		hashMap->put(hashMap, tempList[i].key, tempList[i].value);
 | 
			
		||||
	}
 | 
			
		||||
	free(tempList);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void defaultPut(HashMap hashMap, let key, let value) {
 | 
			
		||||
	// 获取哈希值
 | 
			
		||||
	int index = hashMap->hashCode(hashMap, key);
 | 
			
		||||
 | 
			
		||||
	if (hashMap->list[index].key == NULL) {
 | 
			
		||||
		hashMap->size++;
 | 
			
		||||
		// 该地址为空时直接存储
 | 
			
		||||
		hashMap->list[index].key = key;
 | 
			
		||||
		hashMap->list[index].value = value;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
 | 
			
		||||
		Entry current = &hashMap->list[index];
 | 
			
		||||
		while (current != NULL) {
 | 
			
		||||
			if (hashMap->equal(key, current->key)) {
 | 
			
		||||
				// 对于键值已经存在的直接覆盖
 | 
			
		||||
				current->value = value;
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			current = current->next;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// 发生冲突则创建节点挂到相应位置的next上
 | 
			
		||||
		Entry entry = newEntry();
 | 
			
		||||
		entry->key = key;
 | 
			
		||||
		entry->value = value;
 | 
			
		||||
		entry->next = hashMap->list[index].next;
 | 
			
		||||
		hashMap->list[index].next = entry;
 | 
			
		||||
		hashMap->size++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (hashMap->autoAssign && hashMap->size >= hashMap->listSize) {
 | 
			
		||||
 | 
			
		||||
		// 内存扩充至原来的两倍
 | 
			
		||||
		// *注: 扩充时考虑的是当前存储元素数量与存储空间的大小关系,而不是存储空间是否已经存满,
 | 
			
		||||
		// 例如: 存储空间为10,存入了10个键值对,但是全部冲突了,所以存储空间空着9个,其余的全部挂在一个上面,
 | 
			
		||||
		// 这样检索的时候和遍历查询没有什么区别了,可以简单这样理解,当我存入第11个键值对的时候一定会发生冲突,
 | 
			
		||||
		// 这是由哈希函数本身的特性(取模)决定的,冲突就会导致检索变慢,所以这时候扩充存储空间,对原有键值对进行
 | 
			
		||||
		// 再次散列,会把冲突的数据再次分散开,加快索引定位速度。
 | 
			
		||||
		resetHashMap(hashMap, hashMap->listSize * 2);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let defaultGet(HashMap hashMap, let key) {
 | 
			
		||||
	if (hashMap->exists(hashMap, key)) {
 | 
			
		||||
		int index = hashMap->hashCode(hashMap, key);
 | 
			
		||||
		Entry entry = &hashMap->list[index];
 | 
			
		||||
		while (entry != NULL) {
 | 
			
		||||
			if (hashMap->equal(entry->key, key)) {
 | 
			
		||||
				return entry->value;
 | 
			
		||||
			}
 | 
			
		||||
			entry = entry->next;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let defaultRemove(HashMap hashMap, let key) {
 | 
			
		||||
	int index = hashMap->hashCode(hashMap, key);
 | 
			
		||||
	Entry entry = &hashMap->list[index];
 | 
			
		||||
	if (entry->key == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
    let entryKey = entry->key;
 | 
			
		||||
	Boolean result = False;
 | 
			
		||||
	if (hashMap->equal(entry->key, key)) {
 | 
			
		||||
		hashMap->size--;
 | 
			
		||||
		if (entry->next != NULL) {
 | 
			
		||||
			Entry temp = entry->next;
 | 
			
		||||
			entry->key = temp->key;
 | 
			
		||||
			entry->value = temp->value;
 | 
			
		||||
			entry->next = temp->next;
 | 
			
		||||
			free(temp);
 | 
			
		||||
		}
 | 
			
		||||
        else {
 | 
			
		||||
            entry->key = NULL;
 | 
			
		||||
            entry->value = NULL;
 | 
			
		||||
        }
 | 
			
		||||
		result = True;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		Entry p = entry;
 | 
			
		||||
		entry = entry->next;
 | 
			
		||||
		while (entry != NULL) {
 | 
			
		||||
			if (hashMap->equal(entry->key, key)) {
 | 
			
		||||
				hashMap->size--;
 | 
			
		||||
				p->next = entry->next;
 | 
			
		||||
				free(entry);
 | 
			
		||||
				result = True;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			p = entry;
 | 
			
		||||
			entry = entry->next;
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 如果空间占用不足一半,则释放多余内存
 | 
			
		||||
	if (result && hashMap->autoAssign &&  hashMap->size < hashMap->listSize / 2) {
 | 
			
		||||
		resetHashMap(hashMap, hashMap->listSize / 2);
 | 
			
		||||
	}
 | 
			
		||||
	return entryKey;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Boolean defaultExists(HashMap hashMap, let key) {
 | 
			
		||||
	int index = hashMap->hashCode(hashMap, key);
 | 
			
		||||
	Entry entry = &hashMap->list[index];
 | 
			
		||||
	if (entry->key == NULL) {
 | 
			
		||||
		return False;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		while (entry != NULL) {
 | 
			
		||||
			if (hashMap->equal(entry->key, key)) {
 | 
			
		||||
				return True;
 | 
			
		||||
			}
 | 
			
		||||
			entry = entry->next;
 | 
			
		||||
		}
 | 
			
		||||
		return False;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void defaultClear(HashMap hashMap) {
 | 
			
		||||
	for (int i = 0; i < hashMap->listSize; i++) {
 | 
			
		||||
		// 释放冲突值内存
 | 
			
		||||
		Entry entry = hashMap->list[i].next;
 | 
			
		||||
		while (entry != NULL) {
 | 
			
		||||
			Entry next = entry->next;
 | 
			
		||||
			free(entry);
 | 
			
		||||
			entry = next;
 | 
			
		||||
		}
 | 
			
		||||
		hashMap->list[i].next = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	// 释放存储空间
 | 
			
		||||
	free(hashMap->list);
 | 
			
		||||
	hashMap->list = NULL;
 | 
			
		||||
	hashMap->size = -1;
 | 
			
		||||
	hashMap->listSize = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HashMap createHashMap(HashCode hashCode, Equal equal) {
 | 
			
		||||
	HashMap hashMap = newHashMap();
 | 
			
		||||
	if (hashMap == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	hashMap->size = 0;
 | 
			
		||||
	hashMap->listSize = 8;
 | 
			
		||||
	hashMap->hashCode = hashCode == NULL ? defaultHashCode : hashCode;
 | 
			
		||||
	hashMap->equal = equal == NULL ? defaultEqual : equal;
 | 
			
		||||
	hashMap->exists = defaultExists;
 | 
			
		||||
	hashMap->get = defaultGet;
 | 
			
		||||
	hashMap->put = defaultPut;
 | 
			
		||||
	hashMap->remove = defaultRemove;
 | 
			
		||||
	hashMap->clear = defaultClear;
 | 
			
		||||
	hashMap->autoAssign = True;
 | 
			
		||||
	
 | 
			
		||||
	// 起始分配8个内存空间,溢出时会自动扩充
 | 
			
		||||
	hashMap->list = newEntryList(hashMap->listSize);
 | 
			
		||||
	if (hashMap->list == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	Entry p = hashMap->list;
 | 
			
		||||
	for (int i = 0; i < hashMap->listSize; i++) {
 | 
			
		||||
		p[i].key = p[i].value = p[i].next = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return hashMap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HashMapIterator createHashMapIterator(HashMap hashMap) {
 | 
			
		||||
	HashMapIterator iterator = newHashMapIterator();
 | 
			
		||||
	if (iterator == NULL) {
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	iterator->hashMap = hashMap;
 | 
			
		||||
	iterator->count = 0;
 | 
			
		||||
	iterator->hashCode = -1;
 | 
			
		||||
	iterator->entry = NULL;
 | 
			
		||||
	return iterator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Boolean hasNextHashMapIterator(HashMapIterator iterator) {
 | 
			
		||||
	return iterator->count < iterator->hashMap->size ? True : False;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HashMapIterator nextHashMapIterator(HashMapIterator iterator) {
 | 
			
		||||
	if (hasNextHashMapIterator(iterator)) {
 | 
			
		||||
		if (iterator->entry != NULL && iterator->entry->next != NULL) {
 | 
			
		||||
			iterator->count++;
 | 
			
		||||
			iterator->entry = iterator->entry->next;
 | 
			
		||||
			return iterator;
 | 
			
		||||
		}
 | 
			
		||||
		while (++iterator->hashCode < iterator->hashMap->listSize) {
 | 
			
		||||
			Entry entry = &iterator->hashMap->list[iterator->hashCode];
 | 
			
		||||
			if (entry->key != NULL) {
 | 
			
		||||
				iterator->count++;
 | 
			
		||||
				iterator->entry = entry;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return iterator;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void freeHashMapIterator(HashMapIterator * iterator) {
 | 
			
		||||
	free(*iterator);
 | 
			
		||||
	*iterator = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define Put(map, key, value) map->put(map, (void *)key, (void *)value);
 | 
			
		||||
#define Get(map, key) (char *)map->get(map, (void *)key)
 | 
			
		||||
#define Remove(map, key) map->remove(map, (void *)key)
 | 
			
		||||
#define Existe(map, key) map->exists(map, (void *)key)
 | 
			
		||||
 | 
			
		||||
void TestHash() {
 | 
			
		||||
    HashMap map = createHashMap(NULL, NULL);
 | 
			
		||||
    Put(map, "000123", "Annie");
 | 
			
		||||
    Put(map, "000245", "Bob");
 | 
			
		||||
    Put(map, "000284", "Daniel");
 | 
			
		||||
    Put(map, "000281", "Luna");
 | 
			
		||||
    Put(map, "000587", "Yao");
 | 
			
		||||
    Put(map, "000985", "Li Ming");
 | 
			
		||||
    Put(map, "000852", "Janne");
 | 
			
		||||
 | 
			
		||||
    printf("print the key-values in hashmap:\n");
 | 
			
		||||
    HashMapIterator iterator = createHashMapIterator(map);
 | 
			
		||||
    while (hasNextHashMapIterator(iterator)) {
 | 
			
		||||
        iterator = nextHashMapIterator(iterator);
 | 
			
		||||
        printf("{ key: %s, key: %s, hashcode: %d }\n",
 | 
			
		||||
            (char *)iterator->entry->key, (char *)iterator->entry->value, iterator->hashCode);
 | 
			
		||||
    }
 | 
			
		||||
    printf("key: 000852, exists: %s\n", Existe(map, "000852") ? "true" : "false");
 | 
			
		||||
    printf("000852: %s\n", Get(map, "000852"));
 | 
			
		||||
    printf("remove 000852 %s\n", Remove(map, "000852") ? "true" : "false");
 | 
			
		||||
    printf("key: 000852, exists: %s\n", Existe(map, "000852") ? "true" : "false");
 | 
			
		||||
 | 
			
		||||
    map->clear(map);
 | 
			
		||||
    freeHashMapIterator(&iterator);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIV_SHELL_CMD_FUNCTION(TestHash, Implement hash_map, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,129 @@
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
* @file:    test_hash.h
 | 
			
		||||
* @brief:   a application of test hash function
 | 
			
		||||
* @version: 3.0
 | 
			
		||||
* @author:  Yao wenying
 | 
			
		||||
* @date:    2023/05/26
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef __HASHMAP_H__
 | 
			
		||||
#define __HASHMAP_H__
 | 
			
		||||
 | 
			
		||||
#include<stdlib.h>
 | 
			
		||||
#include<string.h>
 | 
			
		||||
#include<stdio.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 实现数据的基本类型
 | 
			
		||||
// 字符串类型
 | 
			
		||||
#define string char *
 | 
			
		||||
#define newString(str) strcpy((char *)malloc(strlen(str) + 1), str)
 | 
			
		||||
#define NEW(type) (type *)malloc(sizeof(type))
 | 
			
		||||
 | 
			
		||||
// 布尔类型
 | 
			
		||||
enum _Boolean { True = 1, False = 0 };
 | 
			
		||||
typedef enum _Boolean  Boolean;
 | 
			
		||||
 | 
			
		||||
#define let void *
 | 
			
		||||
 | 
			
		||||
typedef struct entry {
 | 
			
		||||
	let key;				// 键
 | 
			
		||||
	let value;				// 值
 | 
			
		||||
	struct entry * next;	// 冲突链表
 | 
			
		||||
}*Entry;
 | 
			
		||||
 | 
			
		||||
#define newEntry() NEW(struct entry)
 | 
			
		||||
#define newEntryList(length) (Entry)malloc(length * sizeof(struct entry))
 | 
			
		||||
 | 
			
		||||
// 哈希结构
 | 
			
		||||
typedef struct hashMap *HashMap;
 | 
			
		||||
 | 
			
		||||
#define newHashMap() NEW(struct hashMap)
 | 
			
		||||
 | 
			
		||||
// 哈希函数类型
 | 
			
		||||
typedef int(*HashCode)(HashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 判等函数类型
 | 
			
		||||
typedef Boolean(*Equal)(let key1, let key2);
 | 
			
		||||
 | 
			
		||||
// 添加键函数类型
 | 
			
		||||
typedef void(*Put)(HashMap hashMap, let key, let value);
 | 
			
		||||
 | 
			
		||||
// 获取键对应值的函数类型
 | 
			
		||||
typedef let(*Get)(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 删除键的函数类型
 | 
			
		||||
typedef let(*Remove)(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 清空Map的函数类型
 | 
			
		||||
typedef void(*Clear)(HashMap hashMap);
 | 
			
		||||
 | 
			
		||||
// 判断键值是否存在的函数类型
 | 
			
		||||
typedef Boolean(*Exists)(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
typedef struct hashMap {
 | 
			
		||||
	int size;			// 当前大小
 | 
			
		||||
	int listSize;		// 有效空间大小
 | 
			
		||||
	HashCode hashCode;	// 哈希函数
 | 
			
		||||
	Equal equal;		// 判等函数
 | 
			
		||||
	Entry list;			// 存储区域
 | 
			
		||||
	Put put;			// 添加键的函数
 | 
			
		||||
	Get get;			// 获取键对应值的函数
 | 
			
		||||
	Remove remove;		// 删除键
 | 
			
		||||
	Clear clear;		// 清空Map
 | 
			
		||||
	Exists exists;		// 判断键是否存在
 | 
			
		||||
	Boolean autoAssign;	// 设定是否根据当前数据量动态调整内存大小,默认开启
 | 
			
		||||
}*HashMap;
 | 
			
		||||
 | 
			
		||||
// 迭代器结构
 | 
			
		||||
typedef struct hashMapIterator {
 | 
			
		||||
	Entry entry;	// 迭代器当前指向
 | 
			
		||||
	int count;		// 迭代次数
 | 
			
		||||
	int hashCode;	// 键值对的哈希值
 | 
			
		||||
	HashMap hashMap;
 | 
			
		||||
}*HashMapIterator;
 | 
			
		||||
 | 
			
		||||
#define newHashMapIterator() NEW(struct hashMapIterator)
 | 
			
		||||
 | 
			
		||||
// 默认哈希函数
 | 
			
		||||
static int defaultHashCode(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 默认判断键值是否相等
 | 
			
		||||
static Boolean defaultEqual(let key1, let key2);
 | 
			
		||||
 | 
			
		||||
// 默认添加键值对
 | 
			
		||||
static void defaultPut(HashMap hashMap, let key, let value);
 | 
			
		||||
 | 
			
		||||
// 默认获取键对应值
 | 
			
		||||
static let defaultGet(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 默认删除键
 | 
			
		||||
static let defaultRemove(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 默认判断键是否存在
 | 
			
		||||
static Boolean defaultExists(HashMap hashMap, let key);
 | 
			
		||||
 | 
			
		||||
// 默认清空Map
 | 
			
		||||
static void defaultClear(HashMap hashMap);
 | 
			
		||||
 | 
			
		||||
// 重新构建
 | 
			
		||||
static void resetHashMap(HashMap hashMap, int listSize);
 | 
			
		||||
 | 
			
		||||
// 创建一个哈希结构
 | 
			
		||||
HashMap createHashMap(HashCode hashCode, Equal equal);
 | 
			
		||||
 | 
			
		||||
// 创建哈希结构迭代器
 | 
			
		||||
HashMapIterator createHashMapIterator(HashMap hashMap);
 | 
			
		||||
 | 
			
		||||
// 迭代器是否有下一个
 | 
			
		||||
Boolean hasNextHashMapIterator(HashMapIterator iterator);
 | 
			
		||||
 | 
			
		||||
// 迭代到下一次
 | 
			
		||||
HashMapIterator nextHashMapIterator(HashMapIterator iterator);
 | 
			
		||||
 | 
			
		||||
// 释放迭代器内存
 | 
			
		||||
void freeHashMapIterator(HashMapIterator * iterator);
 | 
			
		||||
 | 
			
		||||
#endif // !__HASHMAP_H__
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
# 基于k210-emulator实现基数树并测试验证
 | 
			
		||||
 | 
			
		||||
## 1. 简介
 | 
			
		||||
 | 
			
		||||
基于矽璓模拟器k210-emulator,实现基数树,并编写测试程序在shell终端打印结果。
 | 
			
		||||
 | 
			
		||||
## 2. 数据结构设计说明
 | 
			
		||||
 | 
			
		||||
基数树节点设计为:
 | 
			
		||||
 | 
			
		||||
```c
 | 
			
		||||
typedef struct _node {
 | 
			
		||||
    void* value;
 | 
			
		||||
    struct _node* next[NODE_SIZE];
 | 
			
		||||
} node;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
其中,节点在树中的路径即为键,`value` 存储值,`NODE_SIZE` 定义为 128,足以容纳所有 ASCII 值。
 | 
			
		||||
 | 
			
		||||
一共实现了 5 个函数,分别为:
 | 
			
		||||
 | 
			
		||||
- `CreateNode`:创建一个基数树节点
 | 
			
		||||
- `InsertNode`:将一对键值对插入基数树
 | 
			
		||||
- `DeleteNode`:删除指定键的键值对
 | 
			
		||||
- `FindNode`:查找指定键对应的值
 | 
			
		||||
- `DestroyTree`:销毁整个基数树
 | 
			
		||||
 | 
			
		||||
## 3. 测试程序说明
 | 
			
		||||
 | 
			
		||||
测试程序 `TestRadix` 已经注册为 shell 命令,可以调用执行。
 | 
			
		||||
 | 
			
		||||
测试程序定义了以下键值对:
 | 
			
		||||
 | 
			
		||||
```c
 | 
			
		||||
char keys[][MAX_WORD_LEN] = {
 | 
			
		||||
    "what",
 | 
			
		||||
    "where",
 | 
			
		||||
    "why",
 | 
			
		||||
    "how",
 | 
			
		||||
    "hello!",
 | 
			
		||||
    "apple",
 | 
			
		||||
    "12345"
 | 
			
		||||
};
 | 
			
		||||
int values[] = {1, 2, 3, 4, 5, 6, 7};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
1. 程序的第一部分创建了基数树,并且将定义的 7 个键值对的前 6 个插入了基数树,然后分别查找 7 个键,前 6 个均可以找到对应的值,最后一个未插入,因此无法找到
 | 
			
		||||
2. 程序的第二部分从基数树中删除了 `where` 和 `how` 两个键,再次分别查找 7 个键,删除的键值对和未插入的键值对均无法找到
 | 
			
		||||
3. 程序的第三部分重新插入了已删除的 `where` 和未插入过的 `12345` ,再次分别查找 7 个键,新插入的值可以检索到
 | 
			
		||||
4. 程序的第四部分将基数树销毁,再次分别查找 7 个键,所有的键值对均无法找到
 | 
			
		||||
 | 
			
		||||
## 4. 运行结果(##需结合运行测试截图按步骤说明##)
 | 
			
		||||
 | 
			
		||||
1. 在工作区终端中输入命令:`make BOARD=k210-emulator menuconfig`,进入配置页面
 | 
			
		||||

 | 
			
		||||
2. 依次进入 `APP_Framework` -> `Applications` -> `test app` 目录,将 `Enable application test function` 选项置为 `Y`
 | 
			
		||||

 | 
			
		||||
3. 进入 `Enable application test function` 将 `Config test radix tree` 选项置为 `Y`
 | 
			
		||||

 | 
			
		||||
4. 一直选择 `Exit` 退出配置,在最后需要确认的页面选择 `Yes` 保存配置
 | 
			
		||||

 | 
			
		||||
5. 执行编译命令:`make BOARD=k210-emulator`,正常情况下应当编译无误
 | 
			
		||||

 | 
			
		||||
6. 在 `qemu` 中运行:`qemu-system-riscv64 -nographic -machine sifive_u -bios build/XiZi-k210-emulator.elf`
 | 
			
		||||

 | 
			
		||||
7. 在 shell 中运行命令 `TestRadix`,执行结果与预期一致,验证完成。
 | 
			
		||||

 | 
			
		||||
| 
		 After Width: | Height: | Size: 89 KiB  | 
| 
		 After Width: | Height: | Size: 71 KiB  | 
| 
		 After Width: | Height: | Size: 131 KiB  | 
| 
		 After Width: | Height: | Size: 32 KiB  | 
| 
		 After Width: | Height: | Size: 23 KiB  | 
| 
		 After Width: | Height: | Size: 61 KiB  | 
| 
		 After Width: | Height: | Size: 238 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,187 @@
 | 
			
		|||
/**
 | 
			
		||||
* @file:    test_radix_tree.c
 | 
			
		||||
* @brief:   Implement a simple radix tree
 | 
			
		||||
* @version: 1.0
 | 
			
		||||
* @date:    2023/5/24
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <transform.h>
 | 
			
		||||
#include "test_radix_tree.h"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: Create a radix tree node
 | 
			
		||||
 * @return node pointer
 | 
			
		||||
 */
 | 
			
		||||
node* CreateNode()
 | 
			
		||||
{
 | 
			
		||||
    node* n = (node*)malloc(sizeof(node));
 | 
			
		||||
    n->value = NULL;
 | 
			
		||||
    for (int i = 0; i < NODE_SIZE; i++) {
 | 
			
		||||
        n->next[i] = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: Insert a new node to radix tree
 | 
			
		||||
 * @param root - radix tree root
 | 
			
		||||
 * @param key - new node key
 | 
			
		||||
 * @param value - new node value
 | 
			
		||||
 * @return void
 | 
			
		||||
 */
 | 
			
		||||
void InsertNode(node* root, const char* key, void* value)
 | 
			
		||||
{
 | 
			
		||||
    if (root == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    node* cur = root;
 | 
			
		||||
    size_t len = strlen(key);
 | 
			
		||||
    for (size_t i = 0; i < len; i++) {
 | 
			
		||||
        uint8_t b = (uint8_t)key[i];
 | 
			
		||||
        if (cur->next[b] == NULL) {
 | 
			
		||||
            cur->next[b] = CreateNode();
 | 
			
		||||
        }
 | 
			
		||||
        cur = cur->next[b];
 | 
			
		||||
    }
 | 
			
		||||
    cur->value = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: Delete a node from radix tree
 | 
			
		||||
 * @param root - radix tree root
 | 
			
		||||
 * @param key - key which is needed to delete
 | 
			
		||||
 * @return void
 | 
			
		||||
 */
 | 
			
		||||
void DeleteNode(node* root, const char* key)
 | 
			
		||||
{
 | 
			
		||||
    if (root == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    node** cur = &root;
 | 
			
		||||
    size_t len = strlen(key);
 | 
			
		||||
    for (size_t i = 0; i < len; i++) {
 | 
			
		||||
        uint8_t b = (uint8_t)key[i];
 | 
			
		||||
        if ((*cur)->next[b] == NULL) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        cur = &((*cur)->next[b]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((*cur)->value == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (*cur)->value = NULL;
 | 
			
		||||
 | 
			
		||||
    int has_children = 0;
 | 
			
		||||
    for (int i = 0; i < NODE_SIZE; i++) {
 | 
			
		||||
        if ((*cur)->next[i] != NULL) {
 | 
			
		||||
            has_children = 1;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!has_children) {
 | 
			
		||||
        free(*cur);
 | 
			
		||||
        (*cur) = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: find a node by key
 | 
			
		||||
 * @param root - radix tree root
 | 
			
		||||
 * @param key - key which is needed to find
 | 
			
		||||
 * @return value pointer corresponding to key
 | 
			
		||||
 */
 | 
			
		||||
void* FindNode(node* root, const char* key)
 | 
			
		||||
{
 | 
			
		||||
    if (root == NULL) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    node* cur = root;
 | 
			
		||||
    size_t len = strlen(key);
 | 
			
		||||
    for (size_t i = 0; i < len; i++) {
 | 
			
		||||
        uint8_t b = (uint8_t)key[i];
 | 
			
		||||
        if (cur->next[b] == NULL) {
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        cur = cur->next[b];
 | 
			
		||||
    }
 | 
			
		||||
    return cur->value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @description: Destroy the radix tree
 | 
			
		||||
 * @param root - radix tree root
 | 
			
		||||
 * @return void
 | 
			
		||||
 */
 | 
			
		||||
void DestroyTree(node* root)
 | 
			
		||||
{
 | 
			
		||||
    if (root == NULL) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    for (int i = 0; i < NODE_SIZE; i++) {
 | 
			
		||||
        DestroyTree(root->next[i]);
 | 
			
		||||
    }
 | 
			
		||||
    free(root);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TestRadix()
 | 
			
		||||
{
 | 
			
		||||
    char keys[][MAX_WORD_LEN] = {
 | 
			
		||||
        "what",
 | 
			
		||||
        "where",
 | 
			
		||||
        "why",
 | 
			
		||||
        "how",
 | 
			
		||||
        "hello!",
 | 
			
		||||
        "apple",
 | 
			
		||||
        "12345"
 | 
			
		||||
    };
 | 
			
		||||
    int values[] = {1, 2, 3, 4, 5, 6, 7};
 | 
			
		||||
 | 
			
		||||
    printf("\nCreate tree and add key & value:\n");
 | 
			
		||||
    node* root = CreateNode();
 | 
			
		||||
    if (!root) printf("Create node failed.\n");
 | 
			
		||||
 | 
			
		||||
    int num = sizeof(keys) / sizeof(keys[0]);
 | 
			
		||||
    for (int i = 0; i < num - 1; ++i) {
 | 
			
		||||
        InsertNode(root, keys[i], &values[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < num; ++i) {
 | 
			
		||||
        int* v = (int*)FindNode(root, keys[i]);
 | 
			
		||||
        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
			
		||||
        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("\nDelete \"where\" and \"how\":\n");
 | 
			
		||||
    DeleteNode(root, keys[1]);
 | 
			
		||||
    DeleteNode(root, keys[3]);
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < num; ++i) {
 | 
			
		||||
        int* v = (int*)FindNode(root, keys[i]);
 | 
			
		||||
        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
			
		||||
        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("\nInsert \"where\" and \"12345\":\n");
 | 
			
		||||
    InsertNode(root, keys[1], &values[1]);
 | 
			
		||||
    InsertNode(root, keys[6], &values[6]);
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < num; ++i) {
 | 
			
		||||
        int* v = (int*)FindNode(root, keys[i]);
 | 
			
		||||
        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
			
		||||
        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    printf("\nDestroy tree:\n");
 | 
			
		||||
    DestroyTree(root);
 | 
			
		||||
    root = NULL;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < num; ++i) {
 | 
			
		||||
        int* v = (int*)FindNode(root, keys[i]);
 | 
			
		||||
        if (v) printf("keys[%d] \"%s\"'v = %d, values[%d] = %d\n", i, keys[i], *v, i, values[i]);
 | 
			
		||||
        else printf("keys[%d] \"%s\" not found\n", i, keys[i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIV_SHELL_CMD_FUNCTION(TestRadix, Implement a simple radix tree, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
/**
 | 
			
		||||
* @file:    test_radix_tree.h
 | 
			
		||||
* @brief:   Implement a simple radix tree
 | 
			
		||||
* @version: 1.0
 | 
			
		||||
* @date:    2023/5/24
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#define NODE_SIZE 128
 | 
			
		||||
#define MAX_WORD_LEN 128
 | 
			
		||||
 | 
			
		||||
typedef struct _node {
 | 
			
		||||
    void* value;
 | 
			
		||||
    struct _node* next[NODE_SIZE];
 | 
			
		||||
} node;
 | 
			
		||||
 | 
			
		||||
node* CreateNode();
 | 
			
		||||
void InsertNode(node* root, const char* key, void* value);
 | 
			
		||||
void DeleteNode(node* root, const char* key);
 | 
			
		||||
void* FindNode(node* root, const char* key);
 | 
			
		||||
void DestroyTree(node* root);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
# 基于cortex-m4-emulator实现红黑树并测试验证
 | 
			
		||||
 | 
			
		||||
## 1. 简介
 | 
			
		||||
红黑树是一种自平衡的二叉查找树,具有良好的插入、删除和查找性能,本次提交结果为红黑树数据结构的简单实现。test_rbtree.h中定义了红黑树的数据结构和声明插入、删除、查找相关操作函数;test_rbtree.c中为操作函数的定义,并提供了测试函数TestRBTree用于验证红黑树的正确性。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 2. 数据结构设计说明
 | 
			
		||||
 | 
			
		||||
**RBNodeType 结构体**
 | 
			
		||||
用来存储一个红黑树结点的相关信息
 | 
			
		||||
- key:节点的键值
 | 
			
		||||
- left_child:指向左子节点的指针
 | 
			
		||||
- right_child:指向右子节点的指针
 | 
			
		||||
- parent:指向父节点的指针
 | 
			
		||||
- is_red:表示节点的颜色,true表示红色,false表示黑色
 | 
			
		||||
 | 
			
		||||
**RBTreeType 结构体**
 | 
			
		||||
用来存储一个红黑树的相关信息
 | 
			
		||||
- root:指向红黑树的根节点的指针
 | 
			
		||||
- leaf:红黑树的叶节点,由于叶节点并不需要存储数据,故每棵树只分配一个叶节点
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**RBTreeTraversal 函数**
 | 
			
		||||
该函数用于遍历红黑树并打印节点的键值。采用中序遍历的方式,递归地遍历左子树、当前节点和右子树。
 | 
			
		||||
 | 
			
		||||
**RBTreeLeftRotate 函数**
 | 
			
		||||
该函数实现红黑树的左旋转操作。接受一个当前节点指针作为参数,并按照左旋转的规则调整节点和子树的位置。
 | 
			
		||||
 | 
			
		||||
**RBTreeRightRotate 函数**
 | 
			
		||||
该函数实现红黑树的右旋转操作。接受一个当前节点指针作为参数,并按照右旋转的规则调整节点和子树的位置。
 | 
			
		||||
 | 
			
		||||
**InsertFixup 函数**
 | 
			
		||||
该函数用于插入节点后修复红黑树的平衡性。接受一个当前节点指针作为参数,并根据红黑树的性质进行旋转和着色操作,以恢复平衡。
 | 
			
		||||
 | 
			
		||||
**RBTreeInsert 函数**
 | 
			
		||||
该函数用于向红黑树中插入一个新节点。接受一个新节点指针作为参数,并根据新节点的键值插入到适当的位置,然后调用 InsertFixup 进行修复。
 | 
			
		||||
 | 
			
		||||
**DeleteFixup 函数**
 | 
			
		||||
该函数用于删除节点后修复红黑树的平衡性。接受一个当前节点指针作为参数,并根据红黑树的性质进行旋转和着色操作,以恢复平衡。
 | 
			
		||||
 | 
			
		||||
**RBTreeDelete 函数**
 | 
			
		||||
该函数用于从红黑树中删除指定节点。接受一个目标节点指针作为参数,并根据不同的情况进行节点的替换和删除操作,然后调用 DeleteFixup 进行修复。
 | 
			
		||||
 | 
			
		||||
**FindSuccessor 函数**
 | 
			
		||||
该函数用于查找给定节点的后继节点。接受一个当前节点指针作为参数,并在红黑树中找到当前节点的后继节点。
 | 
			
		||||
 | 
			
		||||
**RBTreeSearch 函数**
 | 
			
		||||
该函数用于在红黑树中查找指定键值的节点。接受一个键值作为参数,并在红黑树中进行查找,返回找到的节点指针。
 | 
			
		||||
 | 
			
		||||
## 3. 测试程序说明
 | 
			
		||||
TestRBTree用于验证红黑树的功能和正确性,下面是该程序的使用步骤和说明:
 | 
			
		||||
- 函数中定义一个默认关键字数组,其中包含了20个整数关键字,运行时自动遍历数组构建红黑树,构建完成后中序遍历输出结果,可以根据输出结果验证红黑树的节点顺序以及颜色是否符合预期。
 | 
			
		||||
- 对关键字数组中的每个关键字,在红黑树中进行搜索,并输出找到节点的父节点、左子节点和右子节点的关键字,随后删除该节点。
 | 
			
		||||
- 在每次删除操作后,程序会询问是否显示当前的红黑树。如果输入 "Y" 或 "y",将再次进行中序遍历,并输出当前红黑树中的结点,可以根据输出结果查看结点是否符合预期。当树空时结束程序。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 4. 运行结果(##需结合运行测试截图按步骤说明##)
 | 
			
		||||
 | 
			
		||||
根据默认关键字数组构建红黑树
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
根据键值查找结点,输出相关信息并删除,可以输入'Y'或'y'展示删除后的红黑树
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
到达空树,退出程序
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
| 
		 After Width: | Height: | Size: 65 KiB  | 
| 
		 After Width: | Height: | Size: 36 KiB  | 
| 
		 After Width: | Height: | Size: 125 KiB  | 
| 
						 | 
				
			
			@ -0,0 +1,341 @@
 | 
			
		|||
/*
 | 
			
		||||
* Copyright (c) 2023 AIIT XUOS Lab
 | 
			
		||||
* XiUOS is licensed under Mulan PSL v2.
 | 
			
		||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
			
		||||
* You may obtain a copy of Mulan PSL v2 at:
 | 
			
		||||
*        http://license.coscl.org.cn/MulanPSL2
 | 
			
		||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
			
		||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
			
		||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
			
		||||
* See the Mulan PSL v2 for more details.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* @file:    test_rbtree.c
 | 
			
		||||
* @brief:   a application of red-black tree function
 | 
			
		||||
* @version: 1.0
 | 
			
		||||
* @author:  AIIT XUOS Lab
 | 
			
		||||
* @date:    2023/6/23
 | 
			
		||||
*/
 | 
			
		||||
#include<string.h>
 | 
			
		||||
#include <transform.h>
 | 
			
		||||
#include"test_rbtree.h"
 | 
			
		||||
#ifdef ADD_XIZI_FETURES
 | 
			
		||||
 | 
			
		||||
void RBTreeTraversal(RBTreeType *tree, RBNodeType *node) 
 | 
			
		||||
{
 | 
			
		||||
	if (node != tree->leaf) {
 | 
			
		||||
		RBTreeTraversal(tree, node->left_child);
 | 
			
		||||
		printf("key:%d, color:%s\n", node->key, (node->is_red ? "Red" : "Black"));
 | 
			
		||||
		RBTreeTraversal(tree, node->right_child);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RBNodeType* RBTreeSearch(RBTreeType *tree, int key)
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType* current_node = tree->root;
 | 
			
		||||
    while (current_node != tree->leaf){
 | 
			
		||||
        if (key < current_node->key)
 | 
			
		||||
            current_node = current_node->left_child;
 | 
			
		||||
        else if (key > current_node->key)
 | 
			
		||||
            current_node = current_node->right_child;
 | 
			
		||||
        else
 | 
			
		||||
            return current_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return tree->leaf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RBTreeLeftRotate(RBTreeType *tree, RBNodeType *current_node)
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType* child_node = current_node->right_child;
 | 
			
		||||
 | 
			
		||||
    current_node->right_child = child_node->left_child;
 | 
			
		||||
    if (child_node->left_child != tree->leaf)
 | 
			
		||||
        child_node->left_child->parent = current_node;
 | 
			
		||||
 | 
			
		||||
    child_node->parent = current_node->parent;
 | 
			
		||||
    if (current_node->parent == tree->leaf)
 | 
			
		||||
        tree->root = child_node;
 | 
			
		||||
    else if (current_node == current_node->parent->left_child)
 | 
			
		||||
        current_node->parent->left_child = child_node;
 | 
			
		||||
    else
 | 
			
		||||
        current_node->parent->right_child = child_node;
 | 
			
		||||
    
 | 
			
		||||
    child_node->left_child = current_node;
 | 
			
		||||
    current_node->parent = child_node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RBTreeRightRotate(RBTreeType *tree, RBNodeType* current_node)
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType* child_node = current_node->left_child;
 | 
			
		||||
 | 
			
		||||
    current_node->left_child = child_node->right_child;
 | 
			
		||||
    if (child_node->right_child != tree->leaf)
 | 
			
		||||
        child_node->right_child->parent = current_node;
 | 
			
		||||
 | 
			
		||||
    child_node->parent = current_node->parent;
 | 
			
		||||
    if (current_node->parent == tree->leaf)
 | 
			
		||||
        tree->root = child_node;
 | 
			
		||||
    else if (current_node == current_node->parent->right_child)
 | 
			
		||||
        current_node->parent->right_child = child_node;
 | 
			
		||||
    else
 | 
			
		||||
        current_node->parent->left_child = child_node;
 | 
			
		||||
    
 | 
			
		||||
    child_node->right_child = current_node;
 | 
			
		||||
    current_node->parent = child_node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void InsertFixup(RBTreeType *tree, RBNodeType* current_node)
 | 
			
		||||
{
 | 
			
		||||
    while (current_node->parent->is_red){
 | 
			
		||||
        /* The parent of current_node is the left subtree of the grandfather */
 | 
			
		||||
        if (current_node->parent == current_node->parent->parent->left_child){
 | 
			
		||||
            RBNodeType * uncle_node = current_node->parent->parent->right_child;
 | 
			
		||||
            if (uncle_node->is_red){    /* case1:red uncle and red parent, change color */
 | 
			
		||||
                uncle_node->is_red = false;
 | 
			
		||||
                current_node->parent->is_red = false;
 | 
			
		||||
                current_node->parent->parent->is_red = true;
 | 
			
		||||
 | 
			
		||||
                current_node = current_node->parent->parent;
 | 
			
		||||
            }else{                      /* case2:black uncle and red parent, need rotation */
 | 
			
		||||
                if (current_node->parent->right_child == current_node){
 | 
			
		||||
                    current_node = current_node->parent;
 | 
			
		||||
                    RBTreeLeftRotate(tree, current_node);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                current_node->parent->is_red = false;
 | 
			
		||||
                current_node->parent->parent->is_red = true;
 | 
			
		||||
                RBTreeRightRotate(tree, current_node->parent->parent);
 | 
			
		||||
            }
 | 
			
		||||
        /* The parent of current_node is the right subtree of the grandfather, same with left subtree */
 | 
			
		||||
        }else{
 | 
			
		||||
            RBNodeType * uncle_node = current_node->parent->parent->left_child;
 | 
			
		||||
            if (uncle_node->is_red){
 | 
			
		||||
                uncle_node->is_red = false;
 | 
			
		||||
                current_node->parent->is_red = false;
 | 
			
		||||
                current_node->parent->parent->is_red = true;
 | 
			
		||||
 | 
			
		||||
                current_node = current_node->parent->parent;
 | 
			
		||||
            }else{
 | 
			
		||||
                if (current_node->parent->left_child == current_node){
 | 
			
		||||
                    current_node = current_node->parent;
 | 
			
		||||
                    RBTreeRightRotate(tree, current_node);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                current_node->parent->is_red = false;
 | 
			
		||||
                current_node->parent->parent->is_red = true;
 | 
			
		||||
                RBTreeLeftRotate(tree, current_node->parent->parent);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    tree->root->is_red = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RBTreeInsert(RBTreeType *tree, RBNodeType* new_node)
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType* previous_node = tree->root;
 | 
			
		||||
    RBNodeType* current_node = tree->root;
 | 
			
		||||
 | 
			
		||||
    while (current_node != tree->leaf){
 | 
			
		||||
        previous_node = current_node;
 | 
			
		||||
        if (new_node->key > current_node->key)
 | 
			
		||||
            current_node = current_node->right_child;
 | 
			
		||||
        else if (new_node->key < current_node->key)
 | 
			
		||||
            current_node = current_node->left_child;
 | 
			
		||||
        else
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (previous_node == tree->leaf){
 | 
			
		||||
        tree->root = new_node;
 | 
			
		||||
        tree->root->parent = tree->leaf;
 | 
			
		||||
    }else{
 | 
			
		||||
        new_node->parent = previous_node;
 | 
			
		||||
 | 
			
		||||
        if (previous_node->key > new_node->key)
 | 
			
		||||
            previous_node->left_child = new_node;
 | 
			
		||||
        else
 | 
			
		||||
            previous_node->right_child = new_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    InsertFixup(tree, new_node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RBNodeType* FindSuccessor(RBTreeType *tree, RBNodeType* current_node)
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType* parent_node = current_node->parent;
 | 
			
		||||
    if (current_node->right_child != tree->leaf){
 | 
			
		||||
        current_node = current_node->right_child;
 | 
			
		||||
        while (current_node->left_child != tree->leaf)
 | 
			
		||||
            current_node = current_node->left_child;
 | 
			
		||||
        return current_node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while ((parent_node != tree->leaf) && (current_node == parent_node->right_child)){
 | 
			
		||||
        current_node = parent_node;
 | 
			
		||||
        parent_node = parent_node->parent;
 | 
			
		||||
    }
 | 
			
		||||
    return parent_node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DeleteFixup(RBTreeType *tree, RBNodeType* current_node)
 | 
			
		||||
{
 | 
			
		||||
    while ((current_node != tree->root) && (current_node->is_red == false)){
 | 
			
		||||
        if (current_node == current_node->parent->left_child){
 | 
			
		||||
            
 | 
			
		||||
            RBNodeType* brother_node = current_node->parent->right_child;
 | 
			
		||||
            if (brother_node->is_red){
 | 
			
		||||
                brother_node->is_red = false;
 | 
			
		||||
                current_node->parent->is_red = true;
 | 
			
		||||
                RBTreeLeftRotate(tree, current_node->parent);
 | 
			
		||||
                brother_node = current_node->parent->right_child;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((brother_node->left_child->is_red == false) && (brother_node->right_child->is_red == false)){
 | 
			
		||||
                brother_node->is_red = true;
 | 
			
		||||
                current_node = current_node->parent;
 | 
			
		||||
            }else{
 | 
			
		||||
                if (brother_node->right_child->is_red == false){
 | 
			
		||||
                    brother_node->left_child->is_red = false;
 | 
			
		||||
                    brother_node->is_red = true;
 | 
			
		||||
                    RBTreeRightRotate(tree, brother_node);
 | 
			
		||||
                    brother_node = current_node->parent->right_child;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                brother_node->is_red = current_node->parent->is_red;
 | 
			
		||||
                current_node->parent->is_red = false;
 | 
			
		||||
                brother_node->right_child->is_red = false;
 | 
			
		||||
                RBTreeLeftRotate(tree, current_node->parent);
 | 
			
		||||
                current_node = tree->root;
 | 
			
		||||
            }
 | 
			
		||||
        }else{
 | 
			
		||||
            RBNodeType* brother_node = current_node->parent->left_child;
 | 
			
		||||
            if (brother_node->is_red){
 | 
			
		||||
                brother_node->is_red = false;
 | 
			
		||||
                current_node->parent->is_red = true;
 | 
			
		||||
                RBTreeRightRotate(tree, current_node->parent);
 | 
			
		||||
                brother_node = current_node->parent->left_child;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ((brother_node->left_child->is_red == false) && (brother_node->right_child->is_red == false)){
 | 
			
		||||
                brother_node->is_red = true;
 | 
			
		||||
                current_node = current_node->parent;
 | 
			
		||||
            }else{
 | 
			
		||||
                if (brother_node->left_child->is_red == false){
 | 
			
		||||
                    brother_node->right_child->is_red = false;
 | 
			
		||||
                    brother_node->is_red = true;
 | 
			
		||||
                    RBTreeLeftRotate(tree, brother_node);
 | 
			
		||||
                    brother_node = current_node->parent->left_child;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                brother_node->is_red = current_node->parent->is_red;
 | 
			
		||||
                current_node->parent->is_red = false;
 | 
			
		||||
                brother_node->left_child->is_red = false;
 | 
			
		||||
                RBTreeRightRotate(tree, current_node->parent);
 | 
			
		||||
                current_node = tree->root;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    current_node->is_red = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RBTreeDelete(RBTreeType *tree, RBNodeType* target_node)
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType* delete_node = tree->leaf;
 | 
			
		||||
    RBNodeType* replace_node = tree->leaf;
 | 
			
		||||
 | 
			
		||||
    if ((target_node->left_child == tree->leaf) || (target_node->right_child == tree->leaf))
 | 
			
		||||
        delete_node = target_node;
 | 
			
		||||
    else
 | 
			
		||||
        delete_node = FindSuccessor(tree, target_node);
 | 
			
		||||
    
 | 
			
		||||
    if (delete_node->left_child != tree->leaf) /* successor still has subtree */
 | 
			
		||||
        replace_node = delete_node->left_child;
 | 
			
		||||
    else if (delete_node->right_child != tree->leaf)
 | 
			
		||||
        replace_node = delete_node->right_child;
 | 
			
		||||
    
 | 
			
		||||
    replace_node->parent = delete_node->parent;
 | 
			
		||||
 | 
			
		||||
    if (delete_node->parent == tree->leaf) /* delete a root node */
 | 
			
		||||
        tree->root = replace_node;
 | 
			
		||||
    else if (delete_node == delete_node->parent->left_child)
 | 
			
		||||
        delete_node->parent->left_child = replace_node;
 | 
			
		||||
    else
 | 
			
		||||
        delete_node->parent->right_child = replace_node;
 | 
			
		||||
 | 
			
		||||
    if (delete_node != target_node)
 | 
			
		||||
        target_node->key = delete_node->key;
 | 
			
		||||
    
 | 
			
		||||
    if (delete_node->is_red == false)
 | 
			
		||||
        DeleteFixup(tree, replace_node);
 | 
			
		||||
 | 
			
		||||
    free(delete_node);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void TestRBTree(void)
 | 
			
		||||
{
 | 
			
		||||
    int default_key[] = { 16, 25, 23, 5, 2, 6, 17, 37, 38, 98, 20, 19, 47, 49, 12, 21, 9, 18, 14, 15 };
 | 
			
		||||
    int array_size = sizeof(default_key) / sizeof(default_key[0]);
 | 
			
		||||
    
 | 
			
		||||
    printf("Test Red Black Tree\n");
 | 
			
		||||
    printf("default_key array: ");
 | 
			
		||||
    for (int i = 0; i < array_size; i++)
 | 
			
		||||
        printf("%d  ", default_key[i]);
 | 
			
		||||
    printf("\n%d elements\n", array_size);
 | 
			
		||||
 | 
			
		||||
	RBTreeType *tree = (RBTreeType *)malloc(sizeof(RBTreeType));
 | 
			
		||||
	if (tree == NULL) {
 | 
			
		||||
		printf("malloc failed\n");
 | 
			
		||||
        return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tree->leaf = (RBNodeType*)malloc(sizeof(RBNodeType));
 | 
			
		||||
    tree->leaf->left_child = NULL;
 | 
			
		||||
    tree->leaf->right_child = NULL;
 | 
			
		||||
    tree->leaf->parent = NULL;
 | 
			
		||||
    tree->leaf->is_red = false;
 | 
			
		||||
    tree->leaf->key = -1;
 | 
			
		||||
	tree->root = tree->leaf;
 | 
			
		||||
 | 
			
		||||
	RBNodeType *node = tree->leaf;
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < array_size; i++) {
 | 
			
		||||
		node = (RBNodeType*)malloc(sizeof(RBNodeType));
 | 
			
		||||
        node->left_child = tree->leaf;
 | 
			
		||||
        node->right_child = tree->leaf;
 | 
			
		||||
        node->parent = NULL;
 | 
			
		||||
        node->is_red = true;
 | 
			
		||||
        node->key = default_key[i];
 | 
			
		||||
		printf("insert key[%d]=%d\n",i,default_key[i]);
 | 
			
		||||
		RBTreeInsert(tree, node);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("------------------Inorder Traversal------------------\n");
 | 
			
		||||
	RBTreeTraversal(tree, tree->root);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < array_size; i++) {
 | 
			
		||||
		printf("search key = %d\n", default_key[i]);
 | 
			
		||||
		node = RBTreeSearch(tree, default_key[i]);
 | 
			
		||||
        printf("search succeeded, parent node: %d, left-child: %d, right-child: %d\n", node->parent->key, node->left_child->key, node->right_child->key);
 | 
			
		||||
 | 
			
		||||
    	printf("delete key = %d\n", node->key);
 | 
			
		||||
        RBTreeDelete(tree, node);
 | 
			
		||||
		
 | 
			
		||||
		printf("Show current tree?Y/N \n");
 | 
			
		||||
        char ch;
 | 
			
		||||
        scanf("%c", &ch);
 | 
			
		||||
         if (ch == 'Y' || ch == 'y') {
 | 
			
		||||
            printf("------------------Inorder Traversal Tree After Deletion------------------\n");
 | 
			
		||||
            if (tree->root != tree->leaf)
 | 
			
		||||
	            RBTreeTraversal(tree, tree->root);
 | 
			
		||||
            else
 | 
			
		||||
                printf("the tree is empty.\n");
 | 
			
		||||
        }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIV_SHELL_CMD_FUNCTION(TestRBTree, a red-black tree test sample, PRIV_SHELL_CMD_MAIN_ATTR);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,60 @@
 | 
			
		|||
/*
 | 
			
		||||
* Copyright (c) 2023 AIIT XUOS Lab
 | 
			
		||||
* XiUOS is licensed under Mulan PSL v2.
 | 
			
		||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
			
		||||
* You may obtain a copy of Mulan PSL v2 at:
 | 
			
		||||
*        http://license.coscl.org.cn/MulanPSL2
 | 
			
		||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
			
		||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
			
		||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
			
		||||
* See the Mulan PSL v2 for more details.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* @file:    test_rbtree.h
 | 
			
		||||
* @brief:   a head file of red-black tree structure
 | 
			
		||||
* @version: 1.0
 | 
			
		||||
* @author:  AIIT XUOS Lab
 | 
			
		||||
* @date:    2023/6/23
 | 
			
		||||
*/
 | 
			
		||||
#ifndef REDBLACKTREE_H_
 | 
			
		||||
#define REDBLACKTREE_H_
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
typedef struct RedBlackNode
 | 
			
		||||
{
 | 
			
		||||
    int key;
 | 
			
		||||
    struct RedBlackNode *left_child;
 | 
			
		||||
    struct RedBlackNode *right_child;
 | 
			
		||||
    struct RedBlackNode *parent;
 | 
			
		||||
    bool is_red;
 | 
			
		||||
} RBNodeType;
 | 
			
		||||
 | 
			
		||||
typedef struct RedBlackTree
 | 
			
		||||
{
 | 
			
		||||
    RBNodeType *root;
 | 
			
		||||
    RBNodeType *leaf;
 | 
			
		||||
} RBTreeType;
 | 
			
		||||
 | 
			
		||||
void TestRBTree(void);
 | 
			
		||||
 | 
			
		||||
void RBTreeTraversal(RBTreeType *tree, RBNodeType *node);
 | 
			
		||||
 | 
			
		||||
void RBTreeLeftRotate(RBTreeType *tree, RBNodeType *current_node);
 | 
			
		||||
 | 
			
		||||
void RBTreeRightRotate(RBTreeType *tree, RBNodeType* current_node);
 | 
			
		||||
 | 
			
		||||
void InsertFixup(RBTreeType *tree, RBNodeType* current_node);
 | 
			
		||||
 | 
			
		||||
void RBTreeInsert(RBTreeType *tree, RBNodeType* new_node);
 | 
			
		||||
 | 
			
		||||
void DeleteFixup(RBTreeType *tree, RBNodeType* current_node);
 | 
			
		||||
 | 
			
		||||
void RBTreeDelete(RBTreeType *tree, RBNodeType* target_node);
 | 
			
		||||
 | 
			
		||||
RBNodeType* FindSuccessor(RBTreeType *tree, RBNodeType* current_node);
 | 
			
		||||
 | 
			
		||||
RBNodeType* RBTreeSearch(RBTreeType *tree, int key);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||