Make a tree grow horizontally applying modifications to current node

孤街浪徒 提交于 2019-12-24 08:19:38

问题


Given an input, I am trying to build a tree which should grow horizontally applying transformations to that input and the consequent children.

For example, given the input 'aab' and two transformation rules like:

ab -> bba
b -> ba

A tree like this would need to be built:

I have written the code, but the way I have done it, my tree works vertically, and I don't want that. I need it to work horizontally and I fail to see where/how I would write the recursion. Here is what I have right now:

   #include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct t_string_node {
    struct t_string_node *next;
    char *value;
} string_node;

typedef struct t_transformation_rule {
    struct t_transformation_rule *next;
    char *needle;
    char *replacement;
} transformation_rule;


void findTransformations(char *origin, string_node **transformations, char *needle, char *replacement)
{
    char *str = origin; 

    for (char *p = str; *p != '\0'; p++) {
        if (strncmp(p, needle, strlen(needle)) == 0) {
            char *str_ = malloc(strlen(str)+1+strlen(replacement)-strlen(needle));
            strcpy(str_, str);
            char *p_ = p - str + str_;
            memmove(p_+strlen(replacement), p_+strlen(needle), strlen(p_)+1-strlen(replacement));
            memcpy(p_, replacement, strlen(replacement));
            //Create new string node.
            string_node *transformation; 
            transformation = malloc(sizeof(string_node));
            transformation->value = str_;
            transformation->next = NULL;

            while (*transformations != NULL) {
                transformations = &(*transformations)->next;
            }
            *transformations = transformation;
        }
    }
}

int hasTransformation(char *origin, char *target, transformation_rule *list_of_rules)
{
    int level;
    level = 0;
    int found;

    string_node *current;
    current = malloc(sizeof(string_node));
    current->value = origin;
    current->next = NULL;

    if(list_of_rules == NULL) {
        if (strcmp(origin, target) == 0) {
            printf("Solution in 0 steps");
            return 1;
        } else {
            printf("No solution");
            return 0;
        }
    }

    string_node *transformations;
    transformations = NULL;

    while (current != NULL) {
      findTransformations(current->value, target, &transformations, list_of_rules->needle, list_of_rules->replacement);
      findTransformations(current->value, &transformations, list_of_rules->next->needle, list_of_rules->next->replacement);
      current = current->next;
    }

    while (transformations != NULL) {
        printf("%s \n", transformations->value);
        transformations = transformations->next;
    }

    return 1;
}

void main()
{
  char *input = "aab";
  char *target = "bababab";
  char *needle = "ab";
  char *replacement = "bba";

  transformation_rule *list_of_rules;
  list_of_rules = NULL;
  list_of_rules = malloc(sizeof(transformation_rule));

  list_of_rules->needle = "ab";
  list_of_rules->replacement = "bba";
  list_of_rules->next = NULL;

  //Create another rule
  transformation_rule *new_rule;
  new_rule = malloc(sizeof(transformation_rule));
  new_rule->needle = "b";
  new_rule->replacement = "ba";
  new_rule->next = NULL;
  list_of_rules->next = new_rule;

  int has_trans;

  has_trans = hasTransformation(input, target, list_of_rules);
}

Anybody could help me to realize how would I do this so that the tree grows horizontally instead of vertically?

Thanks


回答1:


@All: This question is a continuation on THIS question (even using the picture i made).

Now the answer to the depth-first vs breadth-first issue: To to this you should not build a tree-datastructure at all. All you have to care about is the current layer and the next layer.

So you just create one list for each. In the beginning you put your start-string in the current and your next is empty. You then see that you can derive abba and aaba so you put them into next. Then you clear current and put everything from next into current and then clear next.

You keep repeating this until you notice that you are adding your target string to next then you can stop searching.

And: As i said in the answer referenced above: This may not terminate and is indecidable whether it will eventually terminate (Halting-problem), BUT there are many heuristics to detect non-termination in specific cases.

EDIT: Ok, here's the code!

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
struct list_s {
    struct list_s* next;
    char* entry;
};
char* paste(char* begin, int len1, char* mid, int len2, char* end, int len3) {
    char* a = malloc(len1+len2+len3+1);
    memcpy(a, begin, len1);
    memcpy(a+len1, mid, len2);
    memcpy(a+len1+len2, end, len3);
    a[len1+len2+len3] = '\0';
    return a;
}
void push(struct list_s** top, char* p) {
    struct list_s* l = malloc(sizeof(struct list_s));
    l->next = *top;
    l->entry = p;
    *top = l;
}
char* pop(struct list_s** top) {
    char* res = (*top)->entry;
    struct list_s* next = (*top)->next;
    free(*top);
    *top = next;
    return res;
}
int main() {
    char* input = "aab";
    // char* target = "bbabaa"; // 11th try
    char* target = "abbaa";     // 5th try
    // char* target = "bababab";// has no solution
    #define cRules 2
    char* from[cRules] = {"ab", "b"}; // ab->bba and b->ba
    char* to[cRules] = {"bba", "ba"};
    struct list_s* current = 0;
    struct list_s* nextLayer = 0;
    char* inputAlloc = malloc(strlen(input));
    strcpy(inputAlloc, input);
    push(&current, inputAlloc);
    int counter = 0;
    while(current) { // = while not empty
        char* cur = pop(&current);
        int lenCur = strlen(cur);
        printf("%s:\n", cur);
        int iRule=0; for(; iRule<cRules; ++iRule) { // for each rule
            char* pos = cur;
            for(;;) { // apply the rule wherever it fits
                pos = strstr(pos, from[iRule]);
                if(!pos) break;
                char* mod = paste(
                    cur, pos-cur, 
                    to[iRule], strlen(to[iRule]), 
                    pos+strlen(from[iRule]), 
                    cur+lenCur-(pos+strlen(from[iRule])) );
                printf("->%s\n", mod);
                if(!strcmp(mod, target)) {
                    printf("DONE\n");
                    return 0;
                }
                push(&nextLayer, mod);
                ++pos;
            }
        }
        free(cur);
        if(!current) { // next round!
            current = nextLayer;
            nextLayer = 0;
        }
        ++counter;
        // here you can add some of the fail-conditions we talked about
        if(counter==100) {
            printf("heuristic: no solution\n");
            return 0;
        }
    }
    return 0;
}


来源:https://stackoverflow.com/questions/15048037/make-a-tree-grow-horizontally-applying-modifications-to-current-node

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!