题目的大致意思是,对于类似 xml 或者 json 格式的数据,进行增、删、改、输出。可见需要用到的算法便是 DFS。
大致思路如下:
- 对初始数据利用 DFS 建立一颗树,方便后续进行增、删、修改、输出。
- 利用哈希算法对其降低运算维度。
- 操作完成后,对步骤 1 进行反向 DFS,输出答案。
建树
根据题意,我们要建的树如下图:
很显然,我们需要利用 DFS 来建立它。每个节点都包含左孩子,右兄弟,当然,每个节点必须有一个父节点。指向父节点的指针没有画出来,自己脑补。
我在建立这颗树的时候,浪费了太多的时间,以致于后面没有时间进行调试。所以,必须熟练的写这个建树过程,达到能够快速码代码。
建立哈希表
一开始我只用了哈希函数,把字符串转化成一个对应的哈希值,然后单单用来进行判断而已。代码如下:
int getHashCode(char s[])
{
ULL ret = 1;
rint i = 0;
while(s[i] != '\0')
{
ret += ((ret << 7) + s[i++] + 3); //(左移7 并且 +2 = 131)
}
return (ret % MAX_NODE_NUM);
}
恩,没错,我只做到这一步。那么每次我去找节点的时候,都得把所有的节点寻找一遍。如下代码:
int findNode(ULL code)
{
for(rint i = 0; i < cnt; i++)//遍历一遍,code为计算出来的哈希值
{
if(node[i].isDelete)
continue;
if(code == node[i].keyCode)
{
return i;
}
}
return -1;
}
实际上,可以利用哈希值创建一个哈希表,根据 key 直接取出结果,而不必遍历,更加优化。每次取值只需调用get()便可,建立哈希表如下:
NODE* hashMap[MAX_NODE_NUM];
//添加节点,key - value
void put(char str[], NODE* node)
{
int key = getHashCode(str);
if(hashMap[key] == 0)
{
hashMap[key] = node;
}
else//哈希冲突链表
{
node->next = hashMap[key];
hashMap[key] = node;
}
}
//获取节点
NODE* get(char str[])
{
int key = getHashCode(str);
NODE* cur = hashMap[key];
if(cur && cur->next == 0)
return cur;
while(cur)//解决哈希冲突
{
if(isSameStr(cur->keyStr, str) == true)//直接比较字符串是否相等
break;
else
cur=cur->next;
}
return cur;
}
增加,删除节点
这一部分,看似没什么好讲,实际上删除节点这部分,我还是踩坑了。一开始我没有采用哈希表的方法,所以删除一个节点后,没有把他的子节点全部标识为删除状态。那么在
findNode(ULL code)
的时候,会去遍历到已经删除的子节点,会导致错误。这需要递归去把他的子节点标识为删除状态。代码如下:
void markForDelete(NODE* tar)
{
if(tar == 0)
return;
tar->isDelete = true;
if(tar->leftChind)//递归遍历这颗子树
{
NODE* rb = tar->leftChind;
markForDelete(rb);
while(rb->rightBro)
{
rb = rb->rightBro;
markForDelete(rb);
}
}
}
当然,改用哈希表的方法不需要这么处理。
总结和完整源码
这到题目的感觉就是,有思路可以做出来啊,但是就是码出不来。原因还是不熟,功力不够,针对这类型的题目还得多写代码。
1)整个核心就是建树过程,添加节点过程,删除过程。这个是最重要的。
2)一定先读懂题意,比如这道题就明确说了最多节点也就400个,要先知道题目确切的意思。确切的数据量大小。
3)先整理思路(要清晰)和搭好框架,然后填代码。
//user code
#define STRINGTYPE 0x01
#define SETTYPE 0x02
#define MAX_KEY_LENGTH 15
#define MAX_VALUE_LENGTH 127
#define MAX_MESSAGE_LENGTH 81920
#define MAX_NODE_NUM (401)
#define ULL unsigned long long
#define rint unsigned register
typedef struct NODE_
{
int type;
char keyStr[MAX_KEY_LENGTH];
int keyLen;
int keyOne;
int keySec;
char valueStr[MAX_VALUE_LENGTH];
int valueLen;
int valueOne;
int valueSec;
NODE_ *parent;
NODE_ *leftChind;
NODE_ *leftBro;
NODE_ *rightBro;
NODE_ *next;
}NODE;
NODE* hashMap[MAX_NODE_NUM];
NODE node[MAX_NODE_NUM];
int cnt=0;
int start = 0;
int target = 0;
NODE *Root;
//tool function
int getHashCode(char s[]);
void ztrDecodecpy(char dest[], const char src[], const int offset, const int length);
void ztrEncodeCpy(char dest[], const char src[], const int offset, const int length);
int ztrlen(const char str[]) ;
void init();
void put(char str[], NODE* node);
NODE* get(char str[]);
bool isSameStr(char s1[], char s2[]);
//build tree and revert tree
void buildSetTree(NODE *par, char in[]);
void revertSetTree(NODE* tar, char out[MAX_MESSAGE_LENGTH]);
//add & del & find node operation
void addChild(NODE* par, NODE* node, bool flag = false);
void delChild(NODE* cur);
void markForDelete(NODE* tar);
//int findNode(ULL code);
bool isSameStr(char s1[], char s2[])
{
bool ret = false;
int len1 = ztrlen(s1);
int len2 = ztrlen(s2);
if(len1 == len2)
{
ret = true;
while(len1--)
{
if(s1[len1] != s2[len1])
{
ret = false;
break;
}
}
}
return ret;
}
void put(char str[], NODE* node)
{
int key = getHashCode(str);
if(hashMap[key] == 0)
{
hashMap[key] = node;
}
else//哈希冲突链表
{
node->next = hashMap[key];
hashMap[key] = node;
}
}
NODE* get(char str[])
{
int key = getHashCode(str);
NODE* cur = hashMap[key];
if(cur && cur->next == 0)
return cur;
while(cur)
{
if(isSameStr(cur->keyStr, str) == true)
break;
else
cur=cur->next;
}
return cur;
}
int getHashCode(char s[])
{
ULL ret = 1;
rint i = 0;
while(s[i] != '\0')
{
ret += ((ret << 7) + s[i++] + 3);
}
return (ret % MAX_NODE_NUM);
}
void init()
{
for(rint i = 0; i < MAX_NODE_NUM; i++)
{
hashMap[i] = 0;
node[i].type = 0;
node[i].keyOne = 0;
node[i].keyLen = 0;
node[i].keySec = 0;
node[i].valueLen = 0;
node[i].valueOne = 0;
node[i].valueSec = 0;
for(rint j = 0; j < MAX_KEY_LENGTH; j++)
{
node[i].keyStr[j] = 0;
}
for(rint j = 0; j < MAX_VALUE_LENGTH; j++)
{
node[i].valueStr[j] = 0;
}
node[i].leftChind = 0;
node[i].rightBro = 0;
node[i].parent = 0;
node[i].leftBro = 0;
node[i].next = 0;
}
cnt = 0;
start = 0;
target = 0;
Root = &node[cnt++];
}
void ztrDecodecpy(char dest[], const char src[], const int offset, const int length)
{
int pos = 0;
while (pos < length && src[pos + offset] != '\0') {
dest[pos] = src[pos + offset];
++pos;
}
dest[pos] = '\0';
}
void ztrEncodeCpy(char dest[], const char src[], const int offset, const int length) {
int pos = 0;
while (pos < length && src[pos] != '\0') {
dest[offset + pos] = src[pos];
++pos;
}
}
int ztrlen(const char str[])
{
int pos = 0;
while(str[pos] != '\0')
++pos;
return pos;
}
void addChild(NODE* par, NODE* node, bool flag)
{
if(par == 0 || node == 0)
return;
put(node->keyStr, node);
node->parent = par;
if(!par->leftChind)
{
par->leftChind = node;
}
else
{
NODE* rb = par->leftChind;
while(rb->rightBro)
{
rb = rb->rightBro;
}
rb->rightBro = node;
}
if(flag == true)
{
par->valueLen++;
par->valueSec = (par->valueLen & 0xff);
par->valueOne = (par->valueLen >> 8);
}
}
void delChild(NODE* cur)
{
if(!cur)
return;
NODE* par = cur->parent;
if(!par)
return;
NODE* rb = par->leftChind;
bool isFind = false;
if(rb == cur)
{
par->leftChind = rb->rightBro;
rb->leftBro = 0;
isFind = true;
}
else
{
while(rb->rightBro)
{
if(rb->rightBro == cur)
{
isFind = true;
break;
}
else
{
rb = rb->rightBro;
}
}
}
if(isFind)
{
rb->rightBro = cur->rightBro;
par->valueLen--;
par->valueOne = par->valueLen >> 8;
par->valueSec = par->valueLen & 0xff;
}
}
void buildSetTree(NODE *par, char in[])
{
int type = in[start];
start++;
NODE* cur = &node[cnt++];
cur->type = type;
//key
cur->keyOne = in[start++];
cur->keySec = in[start++];
cur->keyLen = (cur->keyOne >> 8) + cur->keySec;
ztrDecodecpy(cur->keyStr, in, start, cur->keyLen);
//value
start += cur->keyLen;
cur->valueOne = in[start++];
cur->valueSec = in[start++];
cur->valueLen = (cur->valueOne >> 8) + cur->valueSec;
if(type == STRINGTYPE)
{
ztrDecodecpy(cur->valueStr, in, start, cur->valueLen);
start += cur->valueLen;
}
else
{
//build child
for(rint i = 0; i < cur->valueLen; i++)
{
buildSetTree(cur, in);
}
}
addChild(par, cur);
}
void revertSetTree(NODE* tar, char out[MAX_MESSAGE_LENGTH])
{
int type = tar->type;
out[target++] = type;
out[target++] = tar->keyOne;
out[target++] = tar->keySec;
ztrEncodeCpy(out, tar->keyStr, target, tar->keyLen);
target += tar->keyLen;
out[target++] = tar->valueOne;
out[target++] = tar->valueSec;
if(type == STRINGTYPE)
{
ztrEncodeCpy(out, tar->valueStr, target, tar->valueLen);
target += tar->valueLen;
}
else
{
if(tar->leftChind)
{
NODE* rb = tar->leftChind;
revertSetTree(rb, out);
while(rb->rightBro)
{
rb=rb->rightBro;
revertSetTree(rb, out);
}
}
}
}
void parse(char in[MAX_MESSAGE_LENGTH], int size)
{
init();
buildSetTree(Root, in);
}
void set(char targetkey[MAX_KEY_LENGTH + 1], char newvalue[MAX_VALUE_LENGTH + 1])
{
int len = ztrlen(newvalue);
NODE* cur = get(targetkey);
if(cur == 0)
return;
cur->valueLen = len;
cur->valueOne = len >> 8;
cur->valueSec = len & 0xff;
ztrDecodecpy(cur->valueStr, newvalue, 0, len);
}
void add(char parentkey[MAX_KEY_LENGTH + 1], char childkey[MAX_KEY_LENGTH + 1], char childvalue[MAX_VALUE_LENGTH + 1])
{
int keyLen = ztrlen(childkey);
int valueLen = ztrlen(childvalue);
NODE* par = get(parentkey);
NODE* cur = &node[cnt++];
cur->type = STRINGTYPE;
cur->keyOne = keyLen >> 8;
cur->keySec = keyLen & 0xff;
cur->keyLen = keyLen;
ztrDecodecpy(cur->keyStr, childkey, 0, cur->keyLen);
cur->valueOne = valueLen >> 8;
cur->valueSec = valueLen & 0xff;
cur->valueLen = valueLen;
ztrDecodecpy(cur->valueStr, childvalue, 0, cur->valueLen);
addChild(par, cur, true);
}
void erase(char targetkey[MAX_KEY_LENGTH + 1])
{
NODE* cur = get(targetkey);
if(cur == 0)
return;
delChild(cur);
}
int generate(char targetkey[MAX_KEY_LENGTH + 1], char out[MAX_MESSAGE_LENGTH])
{
target = 0;
NODE* tar = get(targetkey);
if(tar == 0)
return target;
revertSetTree(tar, out);
out[target] = '\0';
return target;
}