線索二叉樹(C語言)

實現下面這棵樹:
先序遍歷: A B C D E F
中序遍歷: C B D A E F
線索二叉樹(C語言)ide

代碼函數

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

typedef enum {links, thread} TAG;

typedef struct treeNode {
    char name;
    struct treeNode *lchild, *rchild;
    TAG ltag;
    TAG rtag;
}TREENODE, *TREE;

void createTree(TREE *);
void traverse(TREE);
void traverse_middle(TREE);
void traverse_middle_detail(TREE);
// 線索化二叉樹,相比普通的中序遍歷,這裏把輸出節點數據的步驟改成了判斷指針域的邏輯
void inThread(TREE, TREE *, TREE);
void traverse_inThread_by_rchild(TREE);

// 調用此函數時須要傳入head
void traverse_inThread_by_rchild(TREE head)
{
    printf("中序正向遍歷二叉鏈表:\n");
    printf("self %p - lc %10p, lt %u, %c, rt %u, rc %10p\n", head, head->lchild, head->ltag, head->name, head->rtag, head->rchild);
    TREE p = head->lchild;
    while (p->lchild != head) {
        p = p->lchild;
        //usleep(100000);
    }

    while (p) {
        printf("self %p - lc %10p, lt %u, %c, rt %u, rc %10p\n", p, p->lchild, p->ltag, p->name, p->rtag, p->rchild);
        p = p->rchild;
    }

}

void inThread(TREE p, TREE *pre, TREE head)
{
    if (! p)
        return;

    inThread(p->lchild, pre, head);
        printf("pre p %p - lc %10p, lt %u, %c, rt %u, rc %10p\n", (*pre), (*pre)->lchild, (*pre)->ltag, (*pre)->name, (*pre)->rtag, (*pre)->rchild);

    // 判斷自身是否有左孩子,若是沒有指向前驅節點
    if (! p->lchild) {
        p->ltag = thread;
        p->lchild = *pre;
    }

    /*
     * 由於遍歷(中序)時,路徑只走到當前節點,並不知道後繼是否有,
     * 因此每一個節點都只處理本身的前驅和前驅的後繼
     *  head節點rchild在第1個節點處理時指向了第1個節點
     */
    if (! (*pre)->rchild) {
        (*pre)->rtag = thread;
        (*pre)->rchild = p;
    }
        printf("    inThread p %p - lc %10p, lt %u, %c, rt %u, rc %10p\n", p, p->lchild, p->ltag, p->name, p->rtag, p->rchild);

    // 本節點處理完後,更新pre指向自身,做爲中序遍歷下一個節點的前驅
    *pre = p;
    // 頭指針rchild指向當前節點,最終線索化完成後,頭節點的右孩子一定指向中序最後1個節點
    head->rchild = p;

    inThread(p->rchild, pre, head);
}

void traverse_middle(TREE p)
{
    if (p) {
        traverse_middle(p->lchild);
        printf("%c ", p->name);
        traverse_middle(p->rchild);
    }
}

void traverse_middle_detail(TREE p)
{
    if (p) {
        traverse_middle_detail(p->lchild);
        printf("self %p - lc %10p, lt %u, %c, rt %u, rc %10p\n", p, p->lchild, p->ltag, p->name, p->rtag, p->rchild);
        traverse_middle_detail(p->rchild);
    }
}

void traverse(TREE p)
{
    if (p) {
        printf("%c ", p->name);
        traverse(p->lchild);
        traverse(p->rchild);
    }
}

// 前序初始化樹的各節點
void createTree(TREE *p)
{
    char c;

    scanf("%c", &c);

    if (c == '_') {
        *p = NULL;
    }
    else {
        *p = (TREE)malloc(sizeof(TREENODE));
        (*p)->name = c;

        // 不管是否會有左右孩子,都先把tag標識爲links
        (*p)->ltag = (*p)->rtag = links;

        createTree(&(*p)->lchild);
        createTree(&(*p)->rchild);
    }

}

int main(void)
{
    // 頭指針,指向線索二叉樹的頭節點(該節點的lchild指向root)
    TREE head = NULL;
    TREE tree;

    head = (TREE)malloc(sizeof(TREENODE));
    head->lchild = head->rchild = NULL;
    head->ltag = head->rtag = thread;
    // 爲了方便確認頭節點
    head->name = 'H';

    TREE pre = head;

    createTree(&tree);
    // 頭節點lchild手動指向tree根節點(rchild已經在線索化完成後指向了中序最後1個節點)
    head->lchild = tree;

    printf("先序遍歷: ");
    traverse(tree);
    putchar('\n');
    printf("中序遍歷: ");
    traverse_middle(tree);
    putchar('\n');
    printf("中序遍歷(detail):\n");
    traverse_middle_detail(tree);
    putchar('\n');

    // 線索化二叉樹(把空閒的lchild, rchild指向各自的前驅和後繼) 
    inThread(tree, &pre, head);

    // 使用rchild遍歷中序線索化的二叉鏈表
    traverse_inThread_by_rchild(head);

    /*
     * 目前中序最後1個節點的rchild依然是NULL,可是已經能夠實現根據頭節點正反向遍歷二叉鏈表
     * 若是按照其它教程裏的須要把中序尾節點rchild的指向頭節點,則中序遍歷記住最後1個指針操做一下就能夠。。。(若是須要判斷空樹等狀況能夠參考網上其它教程)
     */

    return 0;
}

output指針

[root@8be225462e66 c]# gcc thrTree.c && ./a.out
ABC__D__E_F__
先序遍歷: A B C D E F
中序遍歷: C B D A E F
中序遍歷(detail):
self 0x1a83740 - lc      (nil), lt 0, C, rt 0, rc      (nil)
self 0x1a83710 - lc  0x1a83740, lt 0, B, rt 0, rc  0x1a83770
self 0x1a83770 - lc      (nil), lt 0, D, rt 0, rc      (nil)
self 0x1a836e0 - lc  0x1a83710, lt 0, A, rt 0, rc  0x1a837a0
self 0x1a837a0 - lc      (nil), lt 0, E, rt 0, rc  0x1a837d0
self 0x1a837d0 - lc      (nil), lt 0, F, rt 0, rc      (nil)

pre p 0x1a832a0 - lc  0x1a836e0, lt 1, H, rt 1, rc      (nil)
    inThread p 0x1a83740 - lc  0x1a832a0, lt 1, C, rt 0, rc      (nil)
pre p 0x1a83740 - lc  0x1a832a0, lt 1, C, rt 0, rc      (nil)
    inThread p 0x1a83710 - lc  0x1a83740, lt 0, B, rt 0, rc  0x1a83770
pre p 0x1a83710 - lc  0x1a83740, lt 0, B, rt 0, rc  0x1a83770
    inThread p 0x1a83770 - lc  0x1a83710, lt 1, D, rt 0, rc      (nil)
pre p 0x1a83770 - lc  0x1a83710, lt 1, D, rt 0, rc      (nil)
    inThread p 0x1a836e0 - lc  0x1a83710, lt 0, A, rt 0, rc  0x1a837a0
pre p 0x1a836e0 - lc  0x1a83710, lt 0, A, rt 0, rc  0x1a837a0
    inThread p 0x1a837a0 - lc  0x1a836e0, lt 1, E, rt 0, rc  0x1a837d0
pre p 0x1a837a0 - lc  0x1a836e0, lt 1, E, rt 0, rc  0x1a837d0
    inThread p 0x1a837d0 - lc  0x1a837a0, lt 1, F, rt 0, rc      (nil)
中序正向遍歷二叉鏈表:
self 0x1a832a0 - lc  0x1a836e0, lt 1, H, rt 1, rc  0x1a837d0
self 0x1a83740 - lc  0x1a832a0, lt 1, C, rt 1, rc  0x1a83710
self 0x1a83710 - lc  0x1a83740, lt 0, B, rt 0, rc  0x1a83770
self 0x1a83770 - lc  0x1a83710, lt 1, D, rt 1, rc  0x1a836e0
self 0x1a836e0 - lc  0x1a83710, lt 0, A, rt 0, rc  0x1a837a0
self 0x1a837a0 - lc  0x1a836e0, lt 1, E, rt 0, rc  0x1a837d0
self 0x1a837d0 - lc  0x1a837a0, lt 1, F, rt 0, rc      (nil)
[root@8be225462e66 c]#
相關文章
相關標籤/搜索