简体   繁体   English

如何使用父节点打印级别顺序二进制搜索树

[英]How to print level-order binary search tree with parent node

I have been trying to write that ; 我一直在尝试写那;

I will receive a certain number of inputs from a text file and it will continue until -1 -1 (first for student id and second for student grade) 我将从文本文件中接收到一定数量的输入,它将一直持续到-1 -1(第一个输入学生ID,第二个输入学生成绩)

For example; 例如;

121 40
456 50
445 60
123 70
677 80
546 90

My output will be the sorted list of student grades with their ids ( I did this. ) 我的输出将是带有其ID的学生成绩的排序列表(我这样做了。)

My program should also print the binary search tree in the following way (First number represents the student id, second number displays the grade and the number in parenthesis shows the parent node. L represents left child and R represents right child). 我的程序还应该按照以下方式打印二进制搜索树(第一个数字代表学生ID,第二个数字显示成绩,括号中的数字显示父节点。L代表左子节点,R代表右子节点)。

It means the output will be; 这意味着输出将是;

123 70
456 50 (70 L) 546 90 (70 R)
121 40 (50 L) 445 60 (50 R) 677 80 (90 L) 

I wrote this code but there is something that I can not fix. 我写了这段代码,但是有些东西我无法修复。 The printParent() function should be fixed. printParent()函数应该是固定的。 It should print "\\n" every level of tree. 它应该在树的每个级别上打印“ \\ n”。

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

struct node{
    struct node *left;
    int ID;
    int Grade;
    struct node *right;
};

struct node* newNode(int,int);
struct node* insertNode(struct node *node,int id,int grade);
void printTree(struct node *node);
void printParent(struct node*);

int main() {
    struct node *head = NULL;
    FILE *file = fopen("input.txt","r");
    int stdID,grade;
    while (!feof(file)) {
        fscanf(file,"%d %d",&stdID,&grade);
        if (stdID && grade == -1){
            break;}
        else
            head = insertNode(head,stdID,grade);
    }
    printTree(head);

    printf("\n");

    printf("%d %d\n",head->ID,head->Grade);

    printParent(head);


    printf("\n");

    fclose(file);
    return 0;
}
struct node* newNode(int id,int grade){
    struct node *newnode = malloc(sizeof(struct node));
    newnode->ID = id;
    newnode->Grade = grade;
    newnode->left = newnode->right = NULL;
    return newnode;
}
struct node* insertNode(struct node *node,int id,int grade){
    if (node == NULL)
        return newNode(id,grade);
    if ( grade < node->Grade)
        node->left = insertNode(node->left,id,grade);
    else if ( grade >= node->Grade)
        node->right = insertNode(node->right,id,grade);
    return node;
}
void printTree(struct node *node){

    if (node == NULL)
        return;
    printTree(node->left);
    printf("%d %d\n", node->ID,node->Grade);
    printTree(node->right);
}
void printParent(struct node *node){

    struct node *temp = node;

    if (temp == NULL)
        return;
    if (temp->left != NULL){
        printf("%d %d (%d L) ",temp->left->ID,temp->left->Grade,temp->Grade);
    }
    if (temp->right != NULL){
        printf("%d %d (%d R) ",temp->right->ID,temp->right->Grade,temp->Grade);
    }
    printParent(temp->left);
    printParent(temp->right);
}

As noted in the comments, I think you need to be doing a breadth-first search (BFS), keeping track of levels so that you can output a newline when you transition between levels. 如评论中所述,我认为您需要进行广度优先搜索(BFS),跟踪级别,以便在级别之间进行转换时可以输出换行符。

Here is code that does the job reasonably robustly. 这是可以相当可靠地完成这项工作的代码。 It uses a FIFO queue to record which nodes need processing. 它使用FIFO队列记录需要处理的节点。 The queue is moderately robust, but it stops abruptly if asked to add an element for which there isn't room. 队列具有一定程度的鲁棒性,但是如果要求添加没有空间的元素,则队列会突然停止。 Fixing that is doable, but modestly fiddly (dynamic memory allocation, but the hard part is handling the correct copying when the queue array grows but the indexes into the queue are not at the start, which would usually be the case). 修复是可行的,但要适度(动态内存分配,但是最困难的部分是当队列数组增长但队列的索引不在开始时(通常是这种情况)来处理正确的复制)。

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

struct node
{
    struct node *left;
    int ID;
    int Grade;
    struct node *right;
};

struct node *newNode(int, int);
struct node *insertNode(struct node *node, int id, int grade);
void printTree(struct node *node);
void printParent(struct node *);

int main(int argc, char **argv)
{
    const char *name = "input.txt";
    if (argc == 2)
        name = argv[1];
    struct node *head = NULL;
    FILE *file = fopen(name, "r");
    if (file == 0)
    {
        fprintf(stderr, "%s: failed to open file %s for reading\n", argv[0], name);
        return 1;
    }
    printf("File: %s\n", name);
    int stdID, grade;
    while (fscanf(file, "%d %d", &stdID, &grade) == 2)
    {
        if (stdID == -1 && grade == -1)
            break;
        printf("Read: %d %d\n", stdID, grade);
        head = insertNode(head, stdID, grade);
        //printf("Tree:\n");
        //printTree(head);
    }
    fclose(file);

    printf("Completed tree:\n");
    printTree(head);
    printf("\n");

    printf("%3d %3d\n", head->ID, head->Grade);
    printf("Parent tree:\n");
    printParent(head);
    printf("\n");

    return 0;
}

struct node *newNode(int id, int grade)
{
    struct node *newnode = malloc(sizeof(struct node));
    newnode->ID = id;
    newnode->Grade = grade;
    newnode->left = newnode->right = NULL;
    return newnode;
}

struct node *insertNode(struct node *node, int id, int grade)
{
    if (node == NULL)
        return newNode(id, grade);
    if (grade < node->Grade)
        node->left = insertNode(node->left, id, grade);
    else if (grade >= node->Grade)
        node->right = insertNode(node->right, id, grade);
    return node;
}

void printTree(struct node *node)
{
    if (node == NULL)
        return;
    printTree(node->left);
    printf("%3d %3d (0x%.12" PRIXPTR ": 0x%.12" PRIXPTR " - 0x%.12" PRIXPTR ")\n",
           node->ID, node->Grade,
           (uintptr_t)node, (uintptr_t)node->left, (uintptr_t)node->right);
    printTree(node->right);
}

/* Structures to manage BFS - breadth-first search */

struct bfs_node
{
    struct node *parent;
    struct node *child;
    char side[4];           /* "L" or "R" plus padding */
    int level;
};

enum { MAX_QUEUE_SIZE = 100 };
struct bfs_queue
{
    struct bfs_node q[MAX_QUEUE_SIZE];
    size_t q_head;
    size_t q_tail;
};

static void bfs_add(struct bfs_queue *q, struct node *parent, struct node *child, int level, char side)
{
    assert(q != 0 && parent != 0 && child != 0);
    assert(parent->left == child || parent->right == child);
    assert(side == 'L' || side == 'R');
    assert(q->q_head < MAX_QUEUE_SIZE && q->q_tail < MAX_QUEUE_SIZE);
    size_t next = (q->q_head + 1) % MAX_QUEUE_SIZE;
    if (next == q->q_tail)
    {
        fprintf(stderr, "Queue is full\n");
        exit(EXIT_FAILURE);
    }
    q->q[q->q_head] = (struct bfs_node){ .parent = parent, .child = child,
                                         .level = level, .side = { side, '\0' } };
    q->q_head = next;
}

static inline void bfs_init(struct bfs_queue *q)
{
    assert(q != 0);
    q->q_head = q->q_tail = 0;
}

static inline int bfs_empty(const struct bfs_queue *q)
{
    assert(q != 0);
    return (q->q_head == q->q_tail);
}

static struct bfs_node *bfs_remove(struct bfs_queue *q)
{
    if (q->q_tail == q->q_head)
    {
        fprintf(stderr, "cannot remove anything from an empty queue\n");
        exit(EXIT_FAILURE);
    }
    assert(q->q_head < MAX_QUEUE_SIZE && q->q_tail < MAX_QUEUE_SIZE);
    size_t curr = q->q_tail;
    q->q_tail = (q->q_tail + 1) % MAX_QUEUE_SIZE;
    return &q->q[curr];
}

void printParent(struct node *node)
{
    if (node == 0)
    {
        printf("Empty tree\n");
        return;
    }

    int level = 0;
    struct bfs_queue q;
    bfs_init(&q);

    if (node->left)
        bfs_add(&q, node, node->left, level + 1, 'L');
    if (node->right)
        bfs_add(&q, node, node->right, level + 1, 'R');

    printf("Level %d: %3d %3d", level, node->ID, node->Grade);

    while (!bfs_empty(&q))
    {
        struct bfs_node *data = bfs_remove(&q);
        assert(data != 0);
        if (data->level != level)
        {
            assert(data->level == level + 1);
            putchar('\n');
            level = data->level;
            printf("Level %d:", level);
        }
        struct node *child = data->child;
        assert(child != 0);
        if (child->left)
            bfs_add(&q, child, child->left, level + 1, 'L');
        if (child->right)
            bfs_add(&q, child, child->right, level + 1, 'R');
        //printf(" %3d %3d (%3d %s)", child->ID, child->Grade, data->parent->ID, data->side);
        printf(" %3d %3d (%3d %s)", child->ID, child->Grade, data->parent->Grade, data->side);
    }
    putchar('\n');
}

Note the code that reads data has been modified considerably, avoiding the feof() function, and also accepting command line file name rather than just a fixed file name — but defaulting to the original file name. 请注意,读取数据的代码已进行了很大的修改,从而避免了feof()函数,并且还接受命令行文件名,而不只是固定的文件名-但默认为原始文件名。 It also reports errors if it fails to open the file. 如果无法打开文件,它还会报告错误。 While reading, it reports the data it read. 读取时,它报告读取的数据。 For debugging, printing the tree after each line can be helpful until you have it working OK. 为了进行调试,在每行之后打印树可能会有所帮助,直到您确定其工作正常为止。 (The code was OK as posted.) I added the addresses to the printout; (代码按发布的顺序是可以的。)我在打印输出中添加了地址; it helps identify/validate the tree structure. 它有助于识别/验证树结构。

On the given input file with the grades in order, you end up with a lop-sided tree with 6 levels (0..5): 在按顺序排列的给定输入文件上,最终得到带有6个等级(0..5)的侧面树:

File: input.original
Read: 121 40
Read: 456 50
Read: 445 60
Read: 123 70
Read: 677 80
Read: 546 90
Completed tree:
121  40 (0x7FCCD3C00340: 0x000000000000 - 0x7FCCD3C02780)
456  50 (0x7FCCD3C02780: 0x000000000000 - 0x7FCCD3C027A0)
445  60 (0x7FCCD3C027A0: 0x000000000000 - 0x7FCCD3C027C0)
123  70 (0x7FCCD3C027C0: 0x000000000000 - 0x7FCCD3C027E0)
677  80 (0x7FCCD3C027E0: 0x000000000000 - 0x7FCCD3C02800)
546  90 (0x7FCCD3C02800: 0x000000000000 - 0x000000000000)

121  40
Parent tree:
Level 0: 121  40
Level 1: 456  50 ( 40 R)
Level 2: 445  60 ( 50 R)
Level 3: 123  70 ( 60 R)
Level 4: 677  80 ( 70 R)
Level 5: 546  90 ( 80 R)

To get the output requested, you need a different input file: 要获得请求的输出,您需要一个不同的输入文件:

123 70
456 50
546 90
121 40
445 60
677 80

This yields: 这样产生:

File: input.req
Read: 123 70
Read: 456 50
Read: 546 90
Read: 121 40
Read: 445 60
Read: 677 80
Completed tree:
121  40 (0x7F99B94027C0: 0x000000000000 - 0x000000000000)
456  50 (0x7F99B9402780: 0x7F99B94027C0 - 0x7F99B94027E0)
445  60 (0x7F99B94027E0: 0x000000000000 - 0x000000000000)
123  70 (0x7F99B9400340: 0x7F99B9402780 - 0x7F99B94027A0)
677  80 (0x7F99B9402800: 0x000000000000 - 0x000000000000)
546  90 (0x7F99B94027A0: 0x7F99B9402800 - 0x000000000000)

123  70
Parent tree:
Level 0: 123  70
Level 1: 456  50 ( 70 L) 546  90 ( 70 R)
Level 2: 121  40 ( 50 L) 445  60 ( 50 R) 677  80 ( 90 L)

Given the input file: 给定输入文件:

305 8
772 51
140 83
877 53
499 74
183 3
240 21
810 49
159 68
977 36
385 3
252 35
163 76
283 12
740 46
829 42
526 51
401 64
726 65
226 3
902 75

(generated using random numbers between 100 and 999 for the ID, and between 0 and 100 for the grade), the output is: (使用ID的100到999之间的数字,成绩的0到100之间的随机数生成),输出为:

File: input-21.txt
Read: 305 8
Read: 772 51
Read: 140 83
Read: 877 53
Read: 499 74
Read: 183 3
Read: 240 21
Read: 810 49
Read: 159 68
Read: 977 36
Read: 385 3
Read: 252 35
Read: 163 76
Read: 283 12
Read: 740 46
Read: 829 42
Read: 526 51
Read: 401 64
Read: 726 65
Read: 226 3
Read: 902 75
Completed tree:
183   3 (0x7FE3795000A0: 0x000000000000 - 0x7FE379500140)
385   3 (0x7FE379500140: 0x000000000000 - 0x7FE379500260)
226   3 (0x7FE379500260: 0x000000000000 - 0x000000000000)
305   8 (0x7FE379500000: 0x7FE3795000A0 - 0x7FE379500020)
283  12 (0x7FE3795001A0: 0x000000000000 - 0x000000000000)
240  21 (0x7FE3795000C0: 0x7FE3795001A0 - 0x7FE3795000E0)
252  35 (0x7FE379500160: 0x000000000000 - 0x000000000000)
977  36 (0x7FE379500120: 0x7FE379500160 - 0x7FE3795001C0)
829  42 (0x7FE3795001E0: 0x000000000000 - 0x000000000000)
740  46 (0x7FE3795001C0: 0x7FE3795001E0 - 0x000000000000)
810  49 (0x7FE3795000E0: 0x7FE379500120 - 0x000000000000)
772  51 (0x7FE379500020: 0x7FE3795000C0 - 0x7FE379500040)
526  51 (0x7FE379500200: 0x000000000000 - 0x000000000000)
877  53 (0x7FE379500060: 0x7FE379500200 - 0x7FE379500080)
401  64 (0x7FE379500220: 0x000000000000 - 0x7FE379500240)
726  65 (0x7FE379500240: 0x000000000000 - 0x000000000000)
159  68 (0x7FE379500100: 0x7FE379500220 - 0x000000000000)
499  74 (0x7FE379500080: 0x7FE379500100 - 0x7FE379500180)
902  75 (0x7FE379500280: 0x000000000000 - 0x000000000000)
163  76 (0x7FE379500180: 0x7FE379500280 - 0x000000000000)
140  83 (0x7FE379500040: 0x7FE379500060 - 0x000000000000)

305   8
Parent tree:
Level 0: 305   8
Level 1: 183   3 (  8 L) 772  51 (  8 R)
Level 2: 385   3 (  3 R) 240  21 ( 51 L) 140  83 ( 51 R)
Level 3: 226   3 (  3 R) 283  12 ( 21 L) 810  49 ( 21 R) 877  53 ( 83 L)
Level 4: 977  36 ( 49 L) 526  51 ( 53 L) 499  74 ( 53 R)
Level 5: 252  35 ( 36 L) 740  46 ( 36 R) 159  68 ( 74 L) 163  76 ( 74 R)
Level 6: 829  42 ( 46 L) 401  64 ( 68 L) 902  75 ( 76 L)
Level 7: 726  65 ( 64 R)

I experimented with 200 grade records with no problem. 我没有问题地试验了200个成绩记录。 There were 19 levels in the tree for that data, and the level with the most records had 28 records in it. 树中有19个级别的数据,记录最多的级别有28个记录。 It wasn't stressing the queue size, but it should have wrapped around the queue end at least once. 并不是在强调队列的大小,但是它应该至少缠绕一次队列末端。

I'd probably add command line options to control whether to report on data as it is added, and whether to print the addresses when printing the tree, and such like. 我可能会添加命令行选项来控制是否在添加数据时报告数据,以及在打印树时是否打印地址等。 I'd also add code to free the tree, and then be ready to loop over more than one file if given many file names, or process standard input if given no files. 我还将添加代码以释放树,然后如果给出许多文件名,则准备循环一个以上的文件,如果没有给出文件,则准备处理标准输入。 However, that's stepping a bit outside the immediate problem. 但是,这已经超出了当前的问题。

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

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