实现下面这棵树:

先序遍历: A B C D E F

中序遍历: C B D A E F

代码

#include

#include

#include

#include

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]#

c语言线索二叉树作用,线索二叉树(C语言)相关推荐

  1. c语言visit函数作用,[求助]二叉树遍历的程序里面的visit函数如何实现

    [求助]二叉树遍历的程序里面的visit函数如何实现 我在没懂的后面加注释 希望大家指教 #include #include #define MAXSIZE 100 typedef struct bi ...

  2. 循环语句在c语言中的作用是什么,C语言中循环语句的使用

    C语言中的循环语句 在C语言中,有三种类型的循环语句: for语句.while语句和do While语句. 分别介绍如下: 1.for循环语句 for语句格式为: for(表达式1;表达式2;表达式3 ...

  3. continue在c语言中什么作用,continue在c语言中什么意思?

    continue在c语言中是退出循环的意思,continue语句的作用是跳过循环体中剩余的语句而强行执行下一次循环. continue语句的作用是跳过循环体中剩余的语句而强行执行下一次循环.conti ...

  4. c语言开头的作用是什么,C语言为什么开头都加;#includestdio.h有什么作用?

    stdio.h 哪些 是 头文件,里面包含一些常用的 函数 例如 stdio.h里面有 scanf();printf()这些函数,没有stdio就不能用这些函数 在C语言家族程序中,头文件被大量使用. ...

  5. c语言例题功能作用,一篇C语言面试题的汇总

    2015-03-21 06:30:02 阅读( 107 ) 1.    找错 void test1() { char string[10]; //string的长度应该设为11,要给"留出位 ...

  6. 循环语句在c语言中的作用是什么,C语言循环命令运用

    1.C语言的应用 随着计算机的普及用,越来越多的人感觉到现有的计算机的应用不能满足越来越多.越来越复杂的事物处理,所以希望自己能够根据所遇到不同的情况来设计.制作.开发相对灵活的控制程序.这样既可以满 ...

  7. c语言注释的作用文百,C语言注释-C语言行注释-C语言注释块注释-嗨客网

    C语言注释教程 用于注解说明解释程序的文字就是注释,注释提高了代码的阅读性.同时,注释也是一个程序员必须要具有的良好编程习惯.我们应该首先将自己的思想通过注释先整理出来,再用代码去体现. 在 C语言注 ...

  8. 0 在c语言中有什么作用,\0在c语言中代表什么?

    "\0"在c语言中代表"字符串结束符"."\0"的ASCII码为"0",也就是空字符:字符串总是以"\0&qu ...

  9. c语言字符集的作用,1.属于C语言字符集中可显示字符的是()

    一.选项 1.属于C语言字符集中可显示字符的是() A.\ B.\n C.\t D.\b 2.不属于C语言字符集中的符号是() A.\ B.上下一点C.小于等于号 D.^ 3.下列选项中,不是转义字符 ...

最新文章

  1. pytorch笔记——简易回归问题
  2. 一次MySQL性能优化实战(转)
  3. 2线性模型 r语言_多层线性模型在R语言上的实现(三)
  4. aes c语言 逆列混合函数,c语言aes列混合和逆列混合的实现(3页)-原创力文档
  5. python和c先学哪个-Python和C先学哪个好?
  6. tomato(番茄)固件的简单设置截图
  7. C#使用S7NetPlus以及PLCSIM Advanced V3.0实现西门子PLC仿真通讯
  8. python fun函数输入某年某月_Python编程实现输入某年某月某日计算出这一天是该年第几天的方法...
  9. vscode 移动到末尾并且换行快捷键
  10. 专科计算机网络技术综述,高职高专计算机系列教材:计算机网络技术
  11. c++在csv写入汉字_python-opencv表格识别转csv
  12. python压缩图片--指定压缩大小且保真压缩
  13. Ubuntu16.04 安装Pangolin出现错误,已解决(亲测成功)
  14. 计算机乡村少年宫教案,乡村少年宫电脑绘画兴趣小组教案
  15. juju based openstack upgrade (by quqi99)
  16. JavaWeb基础学习2
  17. java的网络协议学习_协议简史:如何学习网络协议?
  18. SK海力士量产业界最高容量的移动端DRAM
  19. 01组团队项目-Beta冲刺-2/5
  20. 信必优再次入围“2015年在华跨国服务外包企业二十强”

热门文章

  1. 8月发布的小米MIX4有什么优缺点
  2. 【硬刚大数据之学习路线篇】2021年从零到大数据专家的学习指南(全面升级版)
  3. 如何理解python的装饰器
  4. 大厂前端面试题总结(浏览器)
  5. STM32MP157驱动开发——Linux并发与竞争
  6. RowMapperT的分析解释
  7. java rowmapper 通用实现_RowMapper实现自动将一行数据映射到指定类的实例中
  8. win7防火墙允许程序列表中没有远程桌面这一项,怎么添加回来
  9. 痛苦网安学习之RootKit
  10. 越南安子山、安子禅院游记