I am trying to transform my C++ code to the Racket since I am learning Racket. My simplified C++ code is:
struct Node
{
char value = '\0';
std::vector<Node> kids;
explicit Node(char ch) : value(ch) {}
};
void ParseTree(const std::string& tokens, size_t& i, Node& root)
{
while (i < tokens.size())
{
const Token& token = tokens[i++];
if (token == '<') // children begin
{
ParseTree(tokens, i, root.kids.back());
}
else if (token == '>') // children end, go up
{
return;
}
else
{
root.kids.emplace_back(token);
}
}
}
Node ParseTree(const std::string& s)
{
size_t i = 0;
Node root('$');
ParseTree(Parse(s), i, root);
return root;
}
So very simple code. My translation to Racket is:
(define (parse-tree tokens)
(if(empty? tokens)
'()
(cond
[(eq? '< (car tokens))
(list (parse-tree (cdr tokens)))]
[(eq? '> (car tokens))
(parse-tree (cdr tokens))] ; no return, how to step up?
[else
(cons (car tokens)(parse-tree (cdr tokens)))])))
The problem here is I am not returning up in (eq? '> (car tokens) so new nodes are added to the bottom. A small test:
(parse-tree '(1 < 2 < 3 4 > > Z < X >))
Should be:
'(1 (2 (3 4)) Z (X))
It is:
'(1 (2 (3 4 Z (X))))
How to fix it?
The problem with your original approach is that you're trying to directly port an imperative solution, one that even uses pass-by-reference to keep track of the state of the traversal. That won't work, the first step would be to rethink the solution in a functional-programming style.
These kinds of problems where we have to keep track of where we're inside a nested structure, are better solved using a stack data structure. I'll use a list to implement a stack of lists, with the following helper for appending a new element on the topmost list:
(define (append-top ele stack)
(cons (append (car stack) (list ele))
(cdr stack)))
Now for the actual solution. Assuming that the input list is well-formed with the same number of <
and >
and in the correct order (no error checking is performed):
(define (parse-tree tokens)
(let parse ([tokens tokens] [stack '(())])
(cond [(null? tokens)
; solution is at the top of the stack, return it
(car stack)]
[(eq? (car tokens) '<)
; start new sublist at the top of the stack
(parse (cdr tokens) (cons '() stack))]
[(eq? (car tokens) '>)
; pop top element of the stack, append it to previous
; frame, continue with solution where we left it
(parse (cdr tokens) (append-top (car stack) (cdr stack)))]
[else
; add current element to top of stack
(parse (cdr tokens) (append-top (car tokens) stack))])))
It works as expected!
(parse-tree '(1 < 2 < 3 4 > > Z < X >))
=> '(1 (2 (3 4)) Z (X))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.