【问题标题】:Iterative Inorder Traversal迭代中序遍历
【发布时间】:2018-01-30 22:08:23
【问题描述】:

这是我的迭代中序遍历函数。 但是当我执行它时,我遇到了分段错误。 我正在使用堆栈进行遍历。在给定的程序中,我还有一个用于中序遍历的递归函数,以检查我的 create() 函数是否正常工作。

我将节点推送到堆栈并移动到节点的左侧,然后我从堆栈中弹出节点并打印它并通过执行向右移动 root=root->rlink.

#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *llink;
struct node *rlink;
}Node;
typedef struct Stack
{
Node *a[10];
int top;
}stack;
void push(stack *s,Node *root)
{
if(s->top==9)
    printf("FULL");
else
{
    s->top++;
    s->a[s->top]=root;
}
}
Node *pop(stack *s)
{
    if(s->top==-1)
        printf("Empty");
    return s->a[s->top--];
}
void inorder(Node *root)
{
    stack s;
    s.top=-1;
    int flag=1;
    while(flag)
    {
    if(s.top!=9)
    {
        push(&s,root);
        root=root->llink;
    }
    else{
        if(s.top!=-1)
        {
            root=pop(&s);
            printf("%d",root->data);
            root=root->rlink;
        }
        else
            flag=0;
    }
    }
}
void inor(Node *root)
{
if(root!=NULL)
{
inor(root->llink);
printf("%d",root->data);
inor(root->rlink);
}
}
Node *create(Node *root,int key)
{
if(root==NULL)
{
root=(Node *)malloc(sizeof(Node));
root->data=key;
root->rlink=root->llink=NULL;
}
else
{
if(key>root->data)
{
    root->rlink=create(root->rlink,key);
}
else if(key<root->data)
{
root->llink=create(root->llink,key);
}
}
return root;
}
int main()
{
    Node *h=NULL;
    h=create(h,5);
    h=create(h,1);
    h=create(h,3);
    h=create(h,8);
    h=create(h,12);
    h=create(h,51);
    inorder(h);
    //inor(h);
}

【问题讨论】:

  • 您是否使用调试器立即找出导致段错误的行并跟踪程序的执行?
  • 确保您使用换行符终止诊断打印消息(或使用fflush(stdout);) - 否则,如果代码崩溃,您可能永远看不到消息,从而给您错误的崩溃发生位置的印象。
  • @kaylum 是的,我做到了,但我想不通
  • @JonathanLeffler Oaky 我会这样做的
  • 好的,那么至少告诉我们哪条线触发了段错误。调试器会立即为您提供。

标签: c data-structures binary-tree binary-search-tree


【解决方案1】:

正如在我的主要comment 中诊断的那样,问题是当该方向上没有更多节点时,您的代码并没有停止向左遍历。修复很简单:

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

typedef struct node
{
    int data;
    struct node *llink;
    struct node *rlink;
} Node;

typedef struct Stack
{
    Node *a[10];
    int top;
} stack;

static
void push(stack *s, Node *root)
{
    if (s->top == 9)
        printf("FULL\n");
    else
    {
        s->top++;
        s->a[s->top] = root;
    }
}

static
Node *pop(stack *s)
{
    if (s->top == -1)
        printf("Empty\n");
    return s->a[s->top--];
}

static
void inorder(Node *root)
{
    stack s;
    s.top = -1;
    int flag = 1;
    while (flag)
    {
        //printf("I: %p\n", (void *)root);
        if (s.top != 9 && root != 0)
        {
            push(&s, root);
            root = root->llink;
        }
        else
        {
            if (s.top != -1)
            {
                root = pop(&s);
                printf(" %d", root->data);
                root = root->rlink;
            }
            else
                flag = 0;
        }
    }
}

static
void inor(Node *root)
{
    if (root != NULL)
    {
        inor(root->llink);
        printf(" %d", root->data);
        inor(root->rlink);
    }
}

static
Node *create(Node *root, int key)
{
    if (root == NULL)
    {
        root = (Node *)malloc(sizeof(Node));
        root->data = key;
        root->rlink = root->llink = NULL;
    }
    else
    {
        if (key > root->data)
        {
            root->rlink = create(root->rlink, key);
        }
        else if (key < root->data)
        {
            root->llink = create(root->llink, key);
        }
    }
    return root;
}

int main(void)
{
    int nodes[] = { 37, 2, 19, 9, 7, 41 };
    enum { NUM_NODES = sizeof(nodes) / sizeof(nodes[0]) };
    Node *h = NULL;
    h = create(h, 5);
    h = create(h, 1);
    h = create(h, 3);
    h = create(h, 8);
    h = create(h, 12);
    h = create(h, 51);
    printf("Recursive:\n");
    inor(h);
    putchar('\n');
    printf("Iterative:\n");
    inorder(h);
    putchar('\n');

    for (int i = 0; i < NUM_NODES; i++)
    {
        h = create(h, nodes[i]);
        printf("Iterative:\n");
        inorder(h);
        putchar('\n');
    }
}

我在函数上使用static,因为我的默认编译器选项要求在使用之前声明或定义函数,并且只有static函数可以在没有预先声明的情况下定义:

gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition it37.c -o it37

您可以自行决定这对您是否重要(但我注意到除此文件之外没有其他文件需要访问这些函数,因此“信息隐藏”建议函数应该是 static)。

样本输出:

Recursive:
 1 3 5 8 12 51
Iterative:
 1 3 5 8 12 51
Iterative:
 1 3 5 8 12 37 51
Iterative:
 1 2 3 5 8 12 37 51
Iterative:
 1 2 3 5 8 12 19 37 51
Iterative:
 1 2 3 5 8 9 12 19 37 51
Iterative:
 1 2 3 5 7 8 9 12 19 37 51
Iterative:
 1 2 3 5 7 8 9 12 19 37 41 51

【讨论】:

    【解决方案2】:

    如上面的 cmets 中给出的,代码中的“root”总是得到左节点的分配地址,当到达叶节点时,它有“NULL”值,你不能访问 null,这就是为什么你的代码失败,会给你分段错误。

    无论如何,这是我的代码解决您的错误

    #include <stdio.h>
    #include <stdlib.h>
    #include<stdbool.h>
    
    
    typedef struct node
    {
        int data;
        struct node *llink;
        struct node *rlink;
    }Node;
    
    
    typedef struct Stack
    {
        Node *a[10];
        int top;
    }stack;
    
    void push(stack *s,Node *root);
    Node *pop(stack *s);
    void inorder(Node *root);
    
    
    
    void push(stack *s,Node *root)
    {
        if(s->top==9)
        {
            printf("FULL");
        }
        else
        {
            s->top++;
            s->a[s->top]=root;
        }
    }
    
    
    Node *pop(stack *s)
    {
        if(s->top==-1)
        {
            printf("Empty");
            return  NULL;
        }
    
        return s->a[s->top--];
    }
    void inorder(Node *root)
    {
        stack *s;// took it as a pointer so that i could use it easily
        s=(stack *)malloc(sizeof(stack));
        s->top=-1;//initialized to -1 because we increment top then insert at location indicated by top
        int flag=1;
        bool traverse_left=true;
    
        while(flag)
        {
            if( root->llink!=NULL && traverse_left )//if left link available go left
            {
                push(s,root);
                root=root->llink;
            }
            else if((root->llink==NULL&&root->rlink!=NULL)||(root->llink!=NULL && !traverse_left))
            {
                printf("%d  ",root->data);
                root=root->rlink;
                traverse_left=true;
            }
            else if(root->llink==NULL&&root->rlink==NULL)
            {
                printf("%d  ",root->data);
                if(root->llink==NULL&&root->rlink==NULL&&s->top==-1)
                {
                    flag=0;
                }
                else
                {
                    root=pop(s);
                }
                traverse_left=false;
            }
    
    
        }
    }
    
    
    void inor(Node *root)
    {
        if(root!=NULL)
        {
            inor(root->llink);
            printf("%d",root->data);
            inor(root->rlink);
        }
    }
    
    Node *create(Node *root,int key)
    {
        if(root==NULL)
        {
            root=(Node *)malloc(sizeof(Node));
            root->data=key;
            root->rlink=root->llink=NULL;
        }
    
        else
        {
            if(key>root->data)
            {
                root->rlink=create(root->rlink,key);
            }
            else if(key<root->data)
            {
                root->llink=create(root->llink,key);
            }
        }
    
    return root;
    }
    int main()
    {
        Node *h=NULL;
    
        h=create(h,5);
        h=create(h,1);
        h=create(h,3);
        h=create(h,8);
        h=create(h,12);
        h=create(h,51);
    
        inorder(h);
        //inor(h);
    }
    
    • 在这个程序中,每当我们寻找左节点时,我都会将该节点放入 在我们移动到左节点之前的堆栈

    • 如果堆栈包含左节点,则在回溯时,这意味着我们已经遍历了它的左树,所以我将其弹出并开始遍历它的右子树

    • 如果一个节点的左右指针为空,我从堆栈中弹出该节点并开始遍历它的右子树

    如果您对此答案有任何疑问,请发表评论。

    【讨论】:

      【解决方案3】:

      中序遍历:左、父、右

      使用栈进行迭代遍历的关键思想是:

      1. 向左走(也推入堆栈)直到找到 null

      2. 运行 while 循环,直到堆栈为空。每次弹出顶部元素,将其添加到结果列表中。然后如果存在右孩子,则转到右孩子(也压入堆栈),然后向左(也压入堆栈)直到找到 null。所以基本上步骤 1 的代码将被复制到 while 循环内。

      代码如下:

      class Node {
          int key;
          Node left, right;
      
          public Node() {}
      
          public Node(int key) {
              this.key = key;
          }
      }
      public List<Integer> inOrderIterative() {
          List<Integer> list = new ArrayList<>();
          Stack<Node> nodeStack = new Stack<>();
          Node current = root;
          nodeStack.push(current);
          while (null != current.left) {
              current = current.left;
              nodeStack.push(current);
          }
      
          while(!nodeStack.empty()) {
              current = nodeStack.pop();
              list.add(current.key);
      
              if (null != current.right) {
                  current = current.right;
                  nodeStack.push(current);
                  while (null != current.left) {
                      current = current.left;
                      nodeStack.push(current);
                  }
              }
          }
      
          return list;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-05-17
        • 2021-10-30
        • 2011-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-10
        • 2016-09-03
        相关资源
        最近更新 更多