ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

机试题 (用 hash 实现部门管理系统 只记得大概的内容,简洁版) -- 上一篇的优化

2021-08-15 23:03:19  阅读:205  来源: 互联网

标签:hash 试题 -- father son test filename optimize


修改点 :

因为做排序需要互换结构体里面的内容, 导致 hashnode 里面保存的 filePtr 指向的内容发生改变, 现在把 hashnode 和 file node 结合在一起 (本来应该合在一起,但之前觉得分开管理清晰一点)

 

#include "common.h"

#define nullptr 0

#define u64 unsigned long long int
#define u32 unsigned int
#define maxstringsize 10

typedef struct LinkNode
{
	u32 depth; // 这个 node 所在的深度, 根目录是0
	u32 mNum;
	u32 create_tm;
	bool is_del;
	char str[maxstringsize];
	LinkNode *father;
	LinkNode *sonlist;
	LinkNode *next; // 用于 sonlist 中链接各个子 node
	//for hash
	u64 hash_value;
	LinkNode *hash_next;
}LinkNode;

#define maxmemsize 1007
static LinkNode g_n_mem[maxmemsize];
static int g_n_mem_cnt = 0;

#define maxhashsize 107
static LinkNode *m_hashmap[maxhashsize];

static char filename[20][maxstringsize]
{
	{"root"},
	{"aaaa"},
	{"bbbb"},
	{"april"},
	{"friday"},
	{"monday"},
	{"love"},
	{"kiss"},
	{"autum"},
	{"weather"},
	{"water"},
	{"leak"},
	{"mouth"},
	{"leader"},
	{"gohome"},
	{"shafa"},
	{"season"},
	{"global"},
	{"see"},
	{"sea"},
};

static LinkNode *root = nullptr;
static u32 g_create_tm = 0;
#define m_max_depth 5 // there is 5 level only

u64 my_hash2(const char str[])
{
	u64 h = 0;
	while (*str != '\0')
	{
		h = h * 26 + (*str++) - 'a' + 1; // 字符串全是小写的情况, 可根据情况改成 31 / 131
	}
	return h & 0xFFFFFFFFFFFFFFFF;
}

u64 my_hash(const char str[])
{
	u64 h = 0;
	u64 p = 1;
	while (*str != '\0')
	{
		h += p * (*str++);
		p *= 2531011;
	}
	return h & 0xFFFFFFFFFFFFFFFF;
}

void add_to_hash_list(LinkNode **phead, LinkNode *pNode)
{
	pNode->hash_next = *phead;
	*phead = pNode;
}

LinkNode *is_exist_in_hash_list(u64 hash_value)
{
	LinkNode *p = m_hashmap[hash_value % maxhashsize];
	while (p != nullptr)
	{
		if (p->hash_value == hash_value)
		{
			return p;
		}
		p = p->hash_next;
	}
	return nullptr;
}

void del_from_hash_list(u64 hash_value)
{
	LOGE("%lld will be del from hash list idx = %d", hash_value, (hash_value % maxhashsize));
	LinkNode *p = m_hashmap[hash_value % maxhashsize];
	if (p->hash_value == hash_value)
	{
		m_hashmap[hash_value % maxhashsize] = p->hash_next;
	}
	else
	{
		LinkNode *pre = p;
		p = p->hash_next;
		while (p != nullptr)
		{
			if (p->hash_value == hash_value)
			{
				pre->hash_next = p->hash_next;
				break; //must has break
			}
			pre = p;
			p = p->hash_next;
		}
	}

	p->hash_value = 0;
	p->hash_next = nullptr;
}

void add_to_father_son_list(LinkNode *father, LinkNode *pNode)
{
	pNode->next = father->sonlist;
	father->sonlist = pNode;
	pNode->father = father;
}

void del_from_father_list(LinkNode *pNode)
{
	LinkNode *p = pNode->father->sonlist;
	if (p == pNode)
	{
		pNode->father->sonlist = p->next;
	}
	else
	{
		LinkNode *pre = p;
		p = p->next;
		while (p != nullptr)
		{
			if (p == pNode)
			{
				pre->next = p->next;
				break; //must has break
			}
			pre = p;
			p = p->next;
		}
	}
}

void init(int mNum)
{
	LOGE("mNum = %d", mNum);
	g_create_tm = 0;

	for (int i = 0; i < maxhashsize; i++)
	{
		m_hashmap[i] = nullptr;
	}
	g_n_mem_cnt = 0;

	//add node
	u64 hash_value = my_hash(filename[0]);
	root = &g_n_mem[g_n_mem_cnt++];
	strcpy_s(root->str, filename[0]);
	root->hash_value = hash_value;
	root->sonlist = nullptr;
	root->next = nullptr;
	root->father = nullptr;
	root->depth = 0;
	root->mNum = mNum;
	root->create_tm = g_create_tm++;
	root->is_del = false;

	//add to hash list
	root->hash_next = nullptr;
	add_to_hash_list(&m_hashmap[root->hash_value % maxhashsize], root);
}

void add_file(char upper[], char newFile[], int mNum)
{
	u64 hash_value = my_hash(upper);
	LinkNode * father = is_exist_in_hash_list(hash_value);
	if (father == nullptr)
	{
		LOGE("there is no upper= %s mNum=%d return %s", upper, mNum, newFile);
		return;
	}
	else if (mNum >= father->mNum)
	{
		LOGE("can not add to upper= %s mNum=%d > %d return %s", upper, mNum, father->mNum, newFile);
		return;
	}

	father->mNum -= mNum;

	LOGE("father = %s %s , son = %s", father->str, upper, newFile);

	//add node
	u64 son_hash_value = my_hash(newFile);
	LinkNode *son = &g_n_mem[g_n_mem_cnt++];
	strcpy_s(son->str, newFile);
	son->hash_value = son_hash_value;
	son->sonlist = nullptr;
	son->next = nullptr;
	son->mNum = mNum;
	son->depth = father->depth + 1;
	son->create_tm = g_create_tm++;
	son->is_del = false;

	//add to hash list
	son->hash_next = nullptr;
	add_to_hash_list(&m_hashmap[son->hash_value % maxhashsize], son);

	//add to father son list
	add_to_father_son_list(father, son);
}

void update_depth(LinkNode *father, u32 *max_depth)
{
	if (father->sonlist == nullptr)
	{
		if (father->depth > *max_depth)
		{
			*max_depth = father->depth;
		}
		return;
	}

	LinkNode *p = father->sonlist;
	while (p != nullptr) {
		p->depth = father->depth + 1;
		update_depth(p, max_depth);
		p = p->next;
	}
}

//如果file 已经存在于 upper 下, 直接返回
//假设深度最大是5, 如果并入 upper 后,总的深度超过5,则直接返回
//合并规则: file 的 mNum 并入 upper 节点, file 的子链表变成 upper 的子链表
void merge_file(char upper[], char file[])
{
	u64 hash_value = my_hash(upper);
	LinkNode * father = is_exist_in_hash_list(hash_value);

	u64 son_hash_value = my_hash(file);
	LinkNode * son = is_exist_in_hash_list(son_hash_value);

	if (father == nullptr || son == nullptr)
		return;

	LOGE("father = %s %s , son = %s %s", father->str, upper, son->str, file);

	u32 max_depth = 0;
	update_depth(son, &max_depth);
	if (father->depth + max_depth - son->depth > m_max_depth)
	{
		LOGE("depth is beyond limit, return depth: %s(%d) %s(%d) max_depth(%d)",
			father->str, father->depth, son->str, son->depth, max_depth);
		return;
	}
	LOGE("max_depth of %s = %d", son->str, max_depth);

	//remove from hash list
	del_from_hash_list(son->hash_value);

	//remove from son list (这里要注意, son 的father 不是当前的 father)
	del_from_father_list(son);

	//add to father son list
	LinkNode *p = son->sonlist;
	while (p != nullptr) {
		// 这里有 BUG, 因为添加到父节点的子链表会导致 next指向改变, 再指行 p=p->next 会错误
		LinkNode *q = p;
		p = p->next;
		add_to_father_son_list(father, q);
	}

	max_depth = 0;
	update_depth(father, &max_depth);

	//remove node
	son->sonlist = nullptr;
	son->father = nullptr;
	son->next = nullptr;
	son->hash_value = 0;
	son->mNum = 0;
	son->depth = 0;
	son->is_del = true;
}

//给排名前 depthNum 的文件增加个数 (除了 root 之外)
//排名规则: 人数最少,优先级最高, 如果人数一样,创建时间越晚,优先级越高
//这里有一个问题, 当直接对 g_n_mem 数组进行冒泡排序, 将会改下对于数组里面的内容
//但由于这个数组对应的 hash 节点里的 *filePtr 还是指向之前的内存, 因此需要同步改 hash

void recuit(u32 depthNum, u32 mNum)
{
	LOGE("depthNum = %d mNum = %d", depthNum, mNum);
	int count = 0;
	for (int i = 1; i < g_n_mem_cnt - 1; i++)
	{
		if (g_n_mem[i].is_del == false)
		{
			count++;
			for (int j = i + 1; j < g_n_mem_cnt; j++)
			{
				if (g_n_mem[j].is_del == false
					&& (g_n_mem[i].mNum > g_n_mem[j].mNum
						|| (g_n_mem[i].mNum > g_n_mem[j].mNum && g_n_mem[i].create_tm < g_n_mem[j].create_tm)))
				{
					LinkNode tmp = g_n_mem[i];
					g_n_mem[i] = g_n_mem[j];
					g_n_mem[j] = tmp;
				}
			}
		}
		if (count >= depthNum)
		{
			break;
		}
	}

	count = 0;
	for (int i = 1; i < g_n_mem_cnt - 1; i++)
	{
		if (g_n_mem[i].is_del == false)
		{
			g_n_mem[i].mNum += mNum;
			count++;
		}
		if (count >= depthNum)
		{
			break;
		}
	}
}

//root->1->3(april)->5(monday)->6(love)->7(kiss)
//root->1->4(friday)
//root->2(bbb)->8(autum)->9(weather)->10(water)

extern void test_hash_optimize()
{
	init(100);
	add_file(filename[0], filename[1], 50);
	add_file(filename[0], filename[2], 40);
	add_file(filename[1], filename[3], 10);
	add_file(filename[1], filename[4], 15);

	add_file(filename[3], filename[5], 5);
	add_file(filename[5], filename[6], 3);
	add_file(filename[6], filename[7], 2);

	add_file(filename[2], filename[8], 7);

	//add fail
	add_file(filename[8], filename[9], 9); //父只有7个,添加失败
	add_file(filename[9], filename[10], 4); //没有父节点,添加失败

	add_file(filename[8], filename[9], 6); //父有7个
	add_file(filename[9], filename[10], 4); // okay
	add_file(filename[9], filename[11], 1); // okay

	//recuit(3, 10);
	merge_file(filename[6], filename[8]);
	merge_file(filename[6], filename[9]);

	//检查 hash 链表 filePtr 是否已经被修改
	for (int i = 0; i < g_n_mem_cnt; i++)
	{
		u64 hash_value = my_hash(filename[i]);
		LinkNode * pNode = is_exist_in_hash_list(hash_value);
		if (pNode != nullptr)
			LOGE("filename[%d] = %s, node str = %s", i, filename[i], pNode->str);
	}
}

 

Log:

e:\c++\c_test\c_test\hash_optimize.cpp init 162 : mNum = 100
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = root root , son = aaaa
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = root root , son = bbbb
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = aaaa aaaa , son = april
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = aaaa aaaa , son = friday
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = april april , son = monday
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = monday monday , son = love
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = love love , son = kiss
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = bbbb bbbb , son = autum
e:\c++\c_test\c_test\hash_optimize.cpp add_file 200 : can not add to upper= autum mNum=9 > 7 return weather
e:\c++\c_test\c_test\hash_optimize.cpp add_file 195 : there is no upper= weather mNum=4 return water
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = autum autum , son = weather
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = weather weather , son = water
e:\c++\c_test\c_test\hash_optimize.cpp add_file 206 : father = weather weather , son = leak
e:\c++\c_test\c_test\hash_optimize.cpp merge_file 261 : father = love love , son = autum autum
e:\c++\c_test\c_test\hash_optimize.cpp merge_file 268 : depth is beyond limit, return depth: love(4) autum(2) max_depth(4)
e:\c++\c_test\c_test\hash_optimize.cpp merge_file 261 : father = love love , son = weather weather
e:\c++\c_test\c_test\hash_optimize.cpp merge_file 271 : max_depth of weather = 4
e:\c++\c_test\c_test\hash_optimize.cpp del_from_hash_list 103 : 2575973297045806516 will be del from hash list idx = 69
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[0] = root, node str = root
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[1] = aaaa, node str = aaaa
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[2] = bbbb, node str = bbbb
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[3] = april, node str = april
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[4] = friday, node str = friday
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[5] = monday, node str = monday
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[6] = love, node str = love
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[7] = kiss, node str = kiss
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[8] = autum, node str = autum
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[10] = water, node str = water
e:\c++\c_test\c_test\hash_optimize.cpp test_hash_optimize 384 : filename[11] = leak, node str = leak
e:\c++\c_test\c_test\c_test.cpp main 37 : process_time = 7.000000

  

标签:hash,试题,--,father,son,test,filename,optimize
来源: https://www.cnblogs.com/Pitter99/p/15145415.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有