DFS 1253 解题报告

来源:互联网 发布:微信斗图软件 编辑:程序博客网 时间:2024/06/04 00:39

题目的大致意思是,对于类似 xml 或者 json 格式的数据,进行增、删、改、输出。可见需要用到的算法便是 DFS。
大致思路如下:

  1. 对初始数据利用 DFS 建立一颗树,方便后续进行增、删、修改、输出。
  2. 利用哈希算法对其降低运算维度。
  3. 操作完成后,对步骤 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 - valuevoid 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 registertypedef 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 functionint 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 treevoid buildSetTree(NODE *par, char in[]);void revertSetTree(NODE* tar, char out[MAX_MESSAGE_LENGTH]);//add & del & find node operationvoid 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;}
原创粉丝点击