当前位置: 首页 > 知识库问答 >
问题:

(普通)树的非递归顺序遍历

倪鹏
2023-03-14

通常为二叉树定义顺序。让我们假设顺序对于(普通)树是“扩展”的。如果树是单个节点,则该节点是树的顺序遍历。如果树T是具有T1,T2,…,的树。。。,Tk子树和r作为根,然后按T1的顺序,然后按r的顺序,然后按T2,T3,…,的顺序遍历。。,Tk是T的顺序遍历。
T以左子右同级表示形式给出。C中节点的数据结构为:

struct node {
   int data;
   struct node *left-child;
   struct node *right-sibling;
}

树用指向根的指针表示。根不能有正确的同级<问题是要找到一种算法来按顺序遍历树。不允许递归。(递归算法很简单)
我试图将算法调整为二叉树,普通树<让我们考虑下面的树:

          1
      /   |   \
     2    3    4

这棵树的顺序是2 1 3 4。
如果我们考虑相应的二叉树:

           1
        /
       2
         \
           3
             \
               4

我们可以看到这个二叉树的顺序是2 3 4 1。我们可以看到普通树的顺序和二叉树之间没有对应关系。
我不知道如何按顺序遍历普通树。
到目前为止我所做的:
绕着树走是我们从根开始,逆时针方向移动,并尽可能靠近树的节点。
对于有序,我们第一次通过叶子时列出它,但第二次通过它时列出内部节点。
这是绕树散步的代码。这是快速黑客,所以我开放的建议和改进。

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

typedef struct tree_node {
  int data;
  struct tree_node *left_child;
  struct tree_node *right_sibling;
} tree_node;


typedef struct stack_node {
  tree_node *data;
  struct stack_node *next;
} stack_node;


void pop( stack_node **p_s )
{
  if( *p_s == NULL ) {
    printf("Error: The stack is empty\n");
  }
  else {
    stack_node *tmp = *p_s;
    *p_s = (*p_s)->next;
    free( tmp );
  }
}

tree_node *top( stack_node *s )
{
  return s->data;
}

void push( tree_node *p_n, stack_node **p_s )
{
  stack_node *tmp = malloc( sizeof( stack_node ) );
  tmp->data = p_n;
  tmp->next = *p_s;
  *p_s = tmp;
}

tree_node *read_tree( void )
{
  printf("Does this tree is empty (y/n):");
  int c = getchar();
  int c1;
  while(( c1 = getchar() ) != '\n' && c1 != EOF );
  if( c == 'y' ) return NULL;
  else {
    tree_node *tmp = malloc( sizeof( tree_node ) );
    tree_node *root = tmp;
    root->right_sibling = NULL;
    stack_node *s = malloc( sizeof( stack_node ) );
    s->data = root;
    s->next = NULL; //Initialize the stack;
    int num_nod;
  state1:
    tmp = top( s );
    printf("Input the data for the node:");
    scanf("%d", &(tmp->data) );
    printf("How many children does this node have (0 for none):");
    scanf("%d", &num_nod);
    if( num_nod == 0 ) {
      tmp->left_child = NULL;
      goto state2;
    }
    else {
      tree_node *tmp2 = malloc( sizeof( tree_node ) );
      push( tmp2, &s );
      tmp->left_child = tmp2;
      for( int i = 1; i < num_nod; i++ ) {
    tmp2->right_sibling = malloc( sizeof( tree_node ) );
    tmp2 = tmp2->right_sibling;
      }
      tmp2->right_sibling = NULL;
      goto state1;
    }
    state2: if( root == top( s ) ) return root;
      tree_node *tmp2 = top( s );
      tmp2 = tmp2->right_sibling;
      pop( &s );
      if( tmp2 == NULL )
    goto state2;
      else {
    push( tmp2, &s );
    goto state1;
      }
  }
}

void walk( tree_node *t )
{
  if( t == NULL ) return;
  stack_node *s = malloc( sizeof( stack_node ) );
  s->data = t;
  s->next = NULL; //Initialize the stack;
  tree_node *tmp;
  tree_node *tmp2;
  tree_node *tmp3;
  printf("%d ", t->data );//We have visited the root, so print it.
  state1:
  tmp = top( s );
  tmp2 = tmp->left_child;
  if( tmp2 == NULL ) {
    goto state2;
  }
  else {
    push( tmp2, &s );
    printf("%d ", tmp2->data );
    goto state1;
  }
  state2:
  tmp = top( s );
  tmp2 = tmp->right_sibling;
  if( tmp == t ) {
    return;
  }
  pop( &s );
  tmp3 = top( s );
  printf("%d ", tmp3->data );
  if( tmp2 == NULL ) goto state2;
  else {
    push( tmp2, &s );
    printf("%d ", tmp2->data );
    goto state1;
 }
} 

int main()
{
  tree_node *t = read_tree();
  walk( t );
}

我们可以通过以下方式实现有序算法。我们可以将指向它们的指针存储在列表中,而不是在walk()函数中列出节点。然后我们可以分析列表中的内部节点,并在它们第二次出现在列表中时列出它们。但是,我不喜欢这个算法。它占用了太多的内存,而且速度很慢。欢迎任何想法。

共有2个答案

邢飞雨
2023-03-14

我想我已经找到了答案:

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

typedef struct tree_node {
  int data;
  struct tree_node *left_child;
  struct tree_node *right_sibling;
} tree_node;


typedef struct stack_node {
  tree_node *data;
  struct stack_node *next;
} stack_node;


void pop( stack_node **p_s )
{
  if( *p_s == NULL ) {
    printf("Error: The stack is empty\n");
  }
  else {
    stack_node *tmp = *p_s;
    *p_s = (*p_s)->next;
    free( tmp );
  }
}

tree_node *top( stack_node *s )
{
  return s->data;
}

void push( tree_node *p_n, stack_node **p_s )
{
  stack_node *tmp = malloc( sizeof( stack_node ) );
  tmp->data = p_n;
  tmp->next = *p_s;
  *p_s = tmp;
}

tree_node *read_tree( void )
{
  printf("Does this tree is empty (y/n):");
  int c = getchar();
  int c1;
  while(( c1 = getchar() ) != '\n' && c1 != EOF );
  if( c == 'y' ) return NULL;
  else {
    tree_node *tmp = malloc( sizeof( tree_node ) );
    tree_node *root = tmp;
    root->right_sibling = NULL;
    stack_node *s = malloc( sizeof( stack_node ) );
    s->data = root;
    s->next = NULL; //Initialize the stack;
    int num_nod;
  state1:
    tmp = top( s );
    printf("Input the data for the node:");
    scanf("%d", &(tmp->data) );
    printf("How many children does this node have (0 for none):");
    scanf("%d", &num_nod);
    if( num_nod == 0 ) {
      tmp->left_child = NULL;
      goto state2;
    }
    else {
      tree_node *tmp2 = malloc( sizeof( tree_node ) );
      push( tmp2, &s );
      tmp->left_child = tmp2;
      for( int i = 1; i < num_nod; i++ ) {
    tmp2->right_sibling = malloc( sizeof( tree_node ) );
    tmp2 = tmp2->right_sibling;
      }
      tmp2->right_sibling = NULL;
      goto state1;
    }
    state2: if( root == top( s ) ) return root;
      tree_node *tmp2 = top( s );
      tmp2 = tmp2->right_sibling;
      pop( &s );
      if( tmp2 == NULL )
    goto state2;
      else {
    push( tmp2, &s );
    goto state1;
      }
  }
}

void nr_inorder( tree_node *t )
{
  if( t == NULL ) return;
  stack_node *s = malloc( sizeof( stack_node ) );
  s->data = t;
  s->next = NULL; //Initialize the stack;
  tree_node *tmp;
  tree_node *tmp2;
  tree_node *tmp3;
  state1:
  tmp = top( s );
  tmp2 = tmp->left_child;
  if( tmp2 == NULL ) { //tmp is a leaf so print it
    printf("%d ", tmp->data );
    goto state2;
  }
  else {
    push( tmp2, &s );
    goto state1;
  }
  state2:
  tmp = top( s );
  tmp2 = tmp->right_sibling;
  if( tmp == t ) {
    return;
  }
  pop( &s );
  tmp3 = top( s );
  if( (tmp3->left_child)->right_sibling == tmp2 ) /* This is the whole trick.
  Basically it states if we are visiting tmp3 for the second time then ... */
    printf("%d ", tmp3->data );
  if( tmp2 == NULL ) goto state2;
  else {
    push( tmp2, &s );
    goto state1;
 }
} 

int main()
{
  tree_node *t = read_tree();
  nr_inorder( t );
}  

这是一个快速破解,我不知道这是否是正确的答案。欢迎提出任何建议和改进。我在几棵树上试过,顺序是正确的。

汤飞
2023-03-14

没有递归的树的有序遍历的标准机制是使用额外的堆栈集合/数据结构。

interwebz提供了这个问题的解决方案,例如,这里有一个youtube视频:https://www.youtube.com/watch?v=kqdtyJPeJ8g

 类似资料:
  • 主要内容:递归实现,非递归实现二叉树后序遍历的实现思想是:从根节点出发,依次遍历各节点的左右子树,直到当前节点左右子树遍历完成后,才访问该节点元素。 图 1 二叉树   如图 1 中,对此二叉树进行后序遍历的操作过程为: 从根节点 1 开始,遍历该节点的左子树(以节点 2 为根节点); 遍历节点 2 的左子树(以节点 4 为根节点); 由于节点 4 既没有左子树,也没有右子树,此时访问该节点中的元素 4,并回退到节点 2 ,遍

  • 主要内容:递归实现,非递归实现二叉树中序遍历的实现思想是: 访问当前节点的左子树; 访问根节点; 访问当前节点的右子树; 图 1 二叉树   以图  1 为例,采用中序遍历的思想遍历该二叉树的过程为: 访问该二叉树的根节点,找到 1; 遍历节点 1 的左子树,找到节点 2; 遍历节点 2 的左子树,找到节点 4; 由于节点 4 无左孩子,因此找到节点 4,并遍历节点 4 的右子树; 由于节点 4 无右子树,因此节点 2 的左子

  • 主要内容:递归实现,非递归实现二叉树先序遍历的实现思想是: 访问根节点; 访问当前节点的左子树; 若当前节点无左子树,则访问当前节点的右子树; 图 1 二叉树   以图  1 为例,采用先序遍历的思想遍历该二叉树的过程为: 访问该二叉树的根节点,找到 1; 访问节点 1 的左子树,找到节点 2; 访问节点 2 的左子树,找到节点 4; 由于访问节点 4 左子树失败,且也没有右子树,因此以节点 4 为根节点的子树遍历完成。但节点

  • 我目前正在研究N进制树,我偶然发现了级序遍历。理论上看起来很简单,在代码上运行并不困难,但是现在我想把它升级并添加递归,这样我就可以更好地理解它。问题是我现在发现很难这样做。这是我的代码: 是否有一种有效的方法,或者递归地运行这种级别顺序遍历方法是否有意义? 这是一些更改后的级别订单代码 它在调用collectNodes的行上给出错误。 这就是collectNodes()的外观。

  • 本文向大家介绍Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】,包括了Java实现的二叉树常用操作【前序建树,前中后递归非递归遍历及层序遍历】的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java实现的二叉树常用操作。分享给大家供大家参考,具体如下: 运行结果: 更多关于java算法相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作

  • 我有一些递归遍历二叉树的代码。 我需要一些帮助来了解正在发生的事情。我了解递归,我知道如何以迭代的顺序遍历二叉树,但似乎看不到这个递归解决方案的效果。 因此,如果'节点'不是无,我们将调用node.left递归函数,直到我们到达一个前导节点,在这种情况下node.left是无,然后我们移动到下一行'result.append(node.val)'? - 这对吗? 然后在“节点”上调用递归函数。对吧