简体   繁体   English

在中序树遍历中将节点推送到堆栈而不是它们的值

[英]Pushing nodes to stack instead their values in an inorder tree traversal

I'm trying to implement a depth first search using a stack in C.我正在尝试使用 C 中的堆栈来实现深度优先搜索。 However, I'm having a lot of difficulty trying to figure out how the stack should be utilized.但是,我很难弄清楚应该如何使用堆栈。 I can only push the value of each tree node onto the stack.我只能将每个树节点的值压入堆栈。 How do I push the node itself so that I can backtrack and find the children of a previous node?如何推送节点本身,以便我可以回溯并找到前一个节点的子节点?

void printorder(struct node* node, struct stack *pt) {
  if (node == NULL) {
    return;
  }

  if (!(node == NULL) || node->visited = false) {
    push(pt,node->data); //pushing root to stack
    int v = pop(&pt);
    printf("Value of pushed node %d",v);
    node->visited = true;
    push(pt,node->left->data);
  }
}

int main(void) {
  struct stack *pt = newStack(9); //Creating new stack with max capacity 9 (amount of nodes we have total)
  struct node *root = newNode(4); //creating root of tree with value 4
  root->left = newNode(7);
  root->right =newNode(98);
  root->left->left = newNode(28);
  root->left->left->left = newNode(77);
  root->left->left->right = newNode(23);
  root->left->right = newNode(86);
  root->left->right->left = newNode(3);
  root->left->right->right = newNode(9);
  printorder(root,pt);    
  return 0;
}

Recursive inorder tree traversal递归中序树遍历

There's no need for an explicit stack for an in order, depth-first tree traversal . 顺序、深度优先的树遍历不需要显式堆栈。 Recursion uses the process' call stack as an implicit data structure.递归使用进程的调用堆栈作为隐式数据结构。 The code you've provided is practically doing this although it appears to conflate the stack push/pop and the recursive calls and is neglecting exploration of the right subtree of root .您提供的代码实际上是这样做的,尽管它似乎将堆栈推送/弹出和递归调用混为一谈,并且忽略了对root右子树的探索。

Here's a minimal example:这是一个最小的例子:

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

struct node {
    int data;
    struct node *left;
    struct node *right;
};

void printInOrder(struct node *root) {
    if (root) {
        printInOrder(root->left);
        printf("%d\n", root->data);
        printInOrder(root->right);
    }
}

struct node *newNode(int data) {
    struct node *result = malloc(sizeof(*result));
    memset(result, 0, sizeof(*result));
    result->data = data;
    return result;
}

void freeTree(struct node *root) {
    if (root) {
        freeTree(root->left);
        freeTree(root->right);
        free(root);
    }
}

int main() {
    /*      0
          /   \
         1     2
       /   \
      3     4
     / \   / \
    5   6 7   8   */
    struct node *root = newNode(0);
    root->left = newNode(1);
    root->right = newNode(2);
    root->left->left = newNode(3);
    root->left->left->left = newNode(5);
    root->left->left->right = newNode(6);
    root->left->right = newNode(4);
    root->left->right->left = newNode(7);
    root->left->right->right = newNode(8);
    printInOrder(root);
    freeTree(root);
    return 0;
}

Iterative inorder tree traversal迭代中序树遍历

If you do need to do this iteratively, you're in for much more work than the recursive version.如果您确实需要迭代地执行此操作,那么您将比递归版本做更多的工作。

The first design choice is whether to make the stack internal to the printInOrder function and use a simple array or to write a stack class.第一个设计选择是是否将堆栈printInOrder function 内部并使用简单数组或编写堆栈 class。 Writing a stack class is a lot more work, but is reusable (it looks like you've already gone down this route).编写堆栈 class 需要做更多的工作,但可以重复使用(看起来你已经走这条路了)。

As for your existing function header, it's a bit unusual to force the caller to allocate resources that should be internal to the function call;至于您现有的 function header,强制调用者分配应该在 function 调用内部的资源有点不寻常; ideally, printInOrder is a generic, stateless black box that the caller can trust to do its job without producing side effects .理想情况下, printInOrder是一个通用的、无状态的黑匣子,调用者可以信任它来完成其工作而不会产生副作用

Imagine making multiple calls to printInOrder using the same stack which might lead to surprising results, or the caller having to worry about allocation/deallocation of this stack.想象一下,使用同一个堆栈对printInOrder进行多次调用,这可能会导致令人惊讶的结果,或者调用者不得不担心这个堆栈的分配/释放。

The traversal algorithm also becomes more complicated.遍历算法也变得更加复杂。 Instead of printing a node's data in the loop, we need to push it on to the stack and traverse to its left child, repeating until the current node is null.我们不需要在循环中打印节点的数据,而是将其压入堆栈并遍历其左子节点,重复直到当前节点为 null。 Then we can print the top of the stack and make the current node the just-printed node's right child.然后我们可以打印栈顶,并使当前节点成为刚刚打印的节点的右孩子。 Repeat until the stack is exhausted.重复直到堆栈耗尽。

Here's the iterative algorithm with an internal stack and works as a drop-in to the above code example:这是具有内部堆栈的迭代算法,可作为上述代码示例的插件:

void printInOrder(struct node *root) {
    int capacity = 4;
    int top = 0;
    struct node **stack = malloc(sizeof(*stack) * capacity);

    for (stack[top] = root; top >= 0;) {
        for (root = stack[top--]; root; root = root->left) {
            if (top >= capacity && 
                !(stack = realloc(stack, sizeof(stack) * (capacity *= 2)))) {
                fprintf(stderr, "%s [%d] realloc failed\n", __FILE__, __LINE__);
                exit(1);
            }

            stack[++top] = root;
        }

        if (top >= 0) {
            root = stack[top--];
            printf("%d\n", root->data);
            stack[++top] = root->right;
        }
    }

    free(stack);
}

Here's a version that uses a stack class.这是一个使用堆栈 class 的版本。 The logic is much cleaner but we've introduced a dependency.逻辑更清晰,但我们引入了依赖项。

stack.h

#ifndef STACK_H
#define STACK_H

#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

struct stack {
    int top;
    int capacity;
    void **entries;
};

struct stack *createStack(int capacity) {
    if (capacity <= 0) return NULL;

    struct stack *s = malloc(sizeof(*s));
    s->top = -1;
    s->capacity = capacity;
    s->entries = malloc(sizeof(*s->entries) * capacity);
    return s;
}

bool empty(struct stack *s) {
    return s->top < 0;
}

void freeStack(struct stack *s) {
    free(s->entries);
    free(s);
}

void *pop(struct stack *stack) {  
    if (stack->top < stack->capacity / 2 - 1) {
        stack->entries = realloc(stack->entries, 
                                 sizeof(stack->entries) * 
                                 (stack->capacity /= 2));
        if (!stack->entries) {
            fprintf(stderr, "%s [%d] realloc failed\n", __FILE__, __LINE__);
            exit(1);
        }
    }

    return stack->entries[stack->top--];
}

void push(struct stack *stack, void *data) {
    if (stack->top >= stack->capacity) {
        stack->entries = realloc(stack->entries, 
                                 sizeof(stack->entries) * 
                                 (stack->capacity *= 2));
        if (!stack->entries) {
            fprintf(stderr, "%s [%d] realloc failed\n", __FILE__, __LINE__);
            exit(1);
        }
    }

    stack->entries[++stack->top] = data;
}

#endif

main.c

#include <stdio.h>
#include <stdlib.h>
#include "stack.h"

struct node {
    int data;
    struct node *left;
    struct node *right;
};

void printInOrder(struct node *root) {
    struct stack *stack = createStack(4);

    for (push(stack, root); !empty(stack);) {
        for (root = pop(stack); root; root = root->left) {
            push(stack, root);
        }

        if (!empty(stack)) {
            root = pop(stack);
            printf("%d\n", root->data);
            push(stack, root->right);
        }
    }

    freeStack(stack);
}

struct node *newNode(int data) {
    struct node *result = malloc(sizeof(*result));
    memset(result, 0, sizeof(*result));
    result->data = data;
    return result;
}

void freeTree(struct node *root) {
    if (root) {
        freeTree(root->left);
        freeTree(root->right);
        free(root);
    }
}

int main() {
    /*      0
          /   \
         1     2
       /   \
      3     4
     / \   / \
    5   6 7   8   */
    struct node *root = newNode(0);
    root->left = newNode(1);
    root->right = newNode(2);
    root->left->left = newNode(3);
    root->left->left->left = newNode(5);
    root->left->left->right = newNode(6);
    root->left->right = newNode(4);
    root->left->right->left = newNode(7);
    root->left->right->right = newNode(8);
    printInOrder(root);
    freeTree(root);
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM