举例讲解C语言程序中对二叉树数据结构的各种遍历方式_C 语言

二叉树遍历的基本思想

二叉树的遍历本质上其实就是入栈出栈的问题,递归算法简单且容易理解,但是效率始终是个问题。非递归算法可以清楚的知道每步实现的细节,但是乍一看不想递归算法那么好理解,各有各的好处吧。接下来根据下图讲讲树的遍历。

1、先序遍历:先序遍历是先输出根节点,再输出左子树,最后输出右子树。上图的先序遍历结果就是:ABCDEF

 2、中序遍历:中序遍历是先输出左子树,再输出根节点,最后输出右子树。上图的中序遍历结果就是:CBDAEF

3、后序遍历:后序遍历是先输出左子树,再输出右子树,最后输出根节点。上图的后序遍历结果就是:CDBFEA

其中,后序遍历的非递归算法是最复杂的,我用了一个标识符isOut来表明是否需要弹出打印。因为只有当节点的左右子树都打印后该节点 才能弹出栈打印,所以标识isOut为1时打印,isOut初始值为0,这主要是为了处理非叶子节点。由后序遍历的原理决定,左右子树都被打印该节点才能打印,所以该节点肯定会被访问2次,第一次的时候不要打印,第二次打印完右子树的时候打印。叶子节点打印完后将isOut置为1。(纯粹是自己想的,应该还有逻辑更简单的算法)
        
实例       
构造和遍历

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

typedef struct _NODE//节点结构
{
  struct _NODE* leftChild;
  int value;
  struct _NODE* rightChild;
} NODE, *PNODE; 

PNODE createNode(int value){//创建一个新节点
  PNODE n = (PNODE)malloc(sizeof(NODE));
  n->value = value;
  n->leftChild = NULL;
  n->rightChild = NULL;
  return n;
} 

PNODE insertLeftChild(PNODE parent, int value){//在指定节点上插入左节点
  return (parent->leftChild = createNode(value));
} 

PNODE insertRightChild(PNODE parent, int value){//在指定节点上插入左节点
  return (parent->rightChild = createNode(value));
} 

void createBTree(PNODE root, int i){//向树中插入一些元素
  if (i == 0)
  {
    return;
  }
  else{
    PNODE l = insertLeftChild(root, i * 10 + 1);
    PNODE r = insertRightChild(root, i * 10 + 2);
    createBTree(l, --i);
    createBTree(r, i);
  }
} 

void printDLR(PNODE root){//先序遍历:对每一刻子树都是根->左->右的顺序
  if (root == NULL)
  {
    return;
  }
  printf("%-4d", root->value);
  printDLR(root->leftChild);
  printDLR(root->rightChild);
} 

void printLDR(PNODE root){//中序遍历:
  if (root == NULL)
  {
    return;
  }
  printLDR(root->leftChild);
  printf("%-4d", root->value);
  printLDR(root->rightChild);
} 

void printLRD(PNODE root){//后序遍历
  if (root == NULL)
  {
    return;
  }
  printLRD(root->leftChild);
  printLRD(root->rightChild);
  printf("%-4d", root->value);
} 

void main(){
  PNODE root = createNode(0);//创建根节点
  createBTree(root, 3); 

  printf("先序遍历: ");
  printDLR(root);//遍历
  printf("\n中序遍历: "); 

  printLDR(root);
  printf("\n后序遍历: "); 

  printLRD(root);
  printf("\n");
}

执行结果:

先序遍历:

中序遍历:

后序遍历:

C++中可以使用类模板,从而使节点值的类型可以不止限定在整型:

#include <iostream.h> 

template <class T> class Node//节点类模板
{
public:
  Node(T value):value(value)//构造方法
  {
    leftChild = 0;
    rightChild = 0;
  }
  Node* insertLeftChild(T value);//插入左孩子,返回新节点指针
  Node* insertRightChild(T vallue);//插入右孩子
  void deleteLeftChild();//删左孩子
  void deleteRightChild();//删右孩子
  void showDLR();//先序遍历
  void showLDR();//中序遍历
  void showLRD();//后序遍历
protected:
  T value;//节点值
  Node* leftChild;//左孩子指针
  Node* rightChild;//右孩子指针
private:
}; 

template <class T> Node<T>* Node<T>::insertLeftChild(T value){//插入左孩子
  return (this->leftChild = new Node(value));
} 

template <class T> Node<T>* Node<T>::insertRightChild(T value){//插入右孩子
  return (this->rightChild = new Node(value));
} 

template <class T> void Node<T>::deleteLeftChild(){//删除左孩子
  delete this->leftChild;
  this->leftChild = 0;
} 

template <class T> void Node<T>::deleteRightChild(){//删除右孩子
  delete this->rightChild;
  this->rightChild = 0;
} 

template <class T> void Node<T>::showDLR(){//先序遍历
  cout<<this->value<<" ";
  if (leftChild)
  {
    leftChild->showDLR();
  }
  if (rightChild)
  {
    rightChild->showDLR();
  }
} 

template <class T> void Node<T>::showLDR(){//中序遍历
  if (leftChild)
  {
    leftChild->showLDR();
  }
  cout<<this->value<<" ";
  if (rightChild)
  {
    rightChild->showLDR();
  }
} 

template <class T> void Node<T>::showLRD(){//后序遍历
  if (leftChild)
  {
    leftChild->showLRD();
  }
  if (rightChild)
  {
    rightChild->showLRD();
  }
  cout<<this->value<<" ";
} 

template <class T> void createSomeNodes(Node<T>* root, int i, T base){//构建一个二叉树
  if (i == 0)
  {
    return;
  }
  Node<T>* l = root->insertLeftChild(i + base);
  Node<T>* r = root->insertRightChild(i + base);
  createSomeNodes(l, --i, base);
  createSomeNodes(r, i, base);
} 

template <class T> void showTest(Node<T>* root){//显示各种遍历方式结果
  cout<<"先序遍历: ";
  root->showDLR();
  cout<<endl<<"中序遍历: ";
  root->showLDR();
  cout<<endl<<"后序遍历: ";
  root->showLRD();
  cout<<endl;
} 

void main(){
  Node<int> *root1 = new Node<int>(0);
  createSomeNodes(root1, 3, 0);
  cout<<"整型:"<<endl;
  showTest(root1); 

  Node<char> *root2 = new Node<char>('a');
  createSomeNodes(root2, 3, 'a');
  cout<<"字符型:"<<endl;
  showTest(root2); 

  Node<float> *root3 = new Node<float>(0.1f);
  createSomeNodes(root3, 3, 0.1f);
  cout<<"浮点型:"<<endl;
  showTest(root3);
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c语言
, 遍历
, 数据结构
二叉树
c语言二叉树遍历、c语言层序遍历二叉树、二叉树遍历算法c语言、遍历二叉树 c语言实现、二叉树的遍历c语言,以便于您获取更多的相关知识。

时间: 2025-01-27 07:15:22

举例讲解C语言程序中对二叉树数据结构的各种遍历方式_C 语言的相关文章

linux c程序中获取shell脚本输出的实现方法_C 语言

1. 前言Unix界有一句名言:"一行shell脚本胜过万行C程序",虽然这句话有些夸张,但不可否认的是,借助脚本确实能够极大的简化一些编程工作.比如实现一个ping程序来测试网络的连通性,实现ping函数需要写上200~300行代码,为什么不能直接调用系统的ping命令呢?通常在程序中通过 system函数来调用shell命令.但是,system函数仅返回命令是否执行成功,而我们可能需要获得shell命令在控制台上输出的结果.例如,执行外部命令ping后,如果执行失败,我们希望得到p

C语言编程中实现二分查找的简单入门实例_C 语言

架设有一个数组 v 已经按升序排列了,数组 v 有 n=20 个元素.数组中有个元素 x,如何知道 x 位于该数组的第几位呢? 解决这个问题的一个普遍方法就是二分查找法.下面是程序: #include <stdio.h> int binsearch(int x, int v[], int n); main() { int i, result, n; int wait; int x = 17; // 需要查找的数值 int v[19]; // 定义一个数组 // 给数组赋值 for(i = 0;

c++二叉树的几种遍历算法_C 语言

1. 前序/中序/后序遍历(递归实现) 复制代码 代码如下: // 前序遍历void BT_PreOrder(BiTreePtr pNode){ if (!pNode)  return;    visit(pNode);   BT_PreOrder(pNode->left); BT_PreOrder(pNode->right);   }// 中序遍历void BT_PreOrder(BiTreePtr pNode){  if (!pNode)  return;     BT_PreOrder(

在C语言编程中设置和获取代码组数的方法_C 语言

C语言setgroups()函数:设置组代码函数头文件: #include <grp.h> 定义函数: int setgroups(size_t size, const gid_t * list); 函数说明:setgroups()用来将list 数组中所标明的组加入到目前进程的组设置中. 参数size 为list()的gid_t 数目, 最大值为NGROUP(32). 返回值:设置成功则返回0, 如有错误则返回-1. 错误代码: EFAULT:参数list 数组地址不合法. EPERM:权限

怎么在c语言程序中一个读入函数

问题描述 怎么在c语言程序中一个读入函数 在c语言中如何读入一个函数 ,并且运用这个函数? 我在编写科学计算器的定积分运算的时候遇到了需要用户自己输入一个函数然后才 能计算该函数的定积分的问题.请问1怎么才能读入一个函数,并利用这个函数呢? 解决方案 http://download.csdn.net/detail/lpw32682770/1587368 解决方案二: 读入函数是什么意思,编译器自带的库里的函数只要引入对应的头文件就可以使用了,如果是封装在DLL里的函数要先获得函数的地址 解决方案

c语言 程序 编译器 栈-C语言程序中,如何理解栈是由编译器管理的?

问题描述 C语言程序中,如何理解栈是由编译器管理的? 最近看书,有一句话"C语言程序中,栈是由编译器自动分配释放的".请问如何理解栈是由编译器管理的? 编译器不是在程序编译链接的时候用的么?而栈是在程序运行的时候产生的.那么如何理解栈是由编译器管理的? 解决方案 C语言对内存的管理的情况是:栈:'自动申请,自动释放',都这么说,栈的申请与释放都是编译器自己进行管理,当程序运行到是在栈上进行的动作的时候,就会自己进行对应的内存的分配与释放,例如,一个变量int a ,编译器会自己申请4字

C++二叉树结构的建立与基本操作_C 语言

准备数据定义二叉树结构操作中需要用到的变量及数据等. 复制代码 代码如下: #define MAXLEN 20    //最大长度typedef char DATA;    //定义元素类型struct  CBTType                   //定义二叉树结点类型 { DATA data;           //元素数据  CBTType * left;    //左子树结点指针  CBTType * right;   //右子树结点指针 }; 定义二叉树结构数据元素的类型DA

详解C语言中的符号常量、变量与算术表达式_C 语言

C语言中的符号常量在结束讨论温度转换程序前,我们再来看一下符号常量.在程序中使用 300.20 等类似的"幻数"并不是一个好习惯,它们几乎无法向以后阅读该程序的人提供什么信息,而且使程序的修改变得更加困难.处理这种幻数的一种方法是赋予它们有意义的名字.#define 指令可以把符号名(或称为符号常量)定义为一个特定的字符串: #define 名字 替换文本 在该定义之后,程序中出现的所有在 #define 中定义的名字(既没有用引号引起来,也不是其它名字的一部分)都将用相应的替换文本替

C语言实现找出二叉树中某个值的所有路径的方法_C 语言

本文实例讲述了C语言实现找出二叉树中某个值的所有路径的方法,是非常常用的一个实用算法技巧.分享给大家供大家参考. 具体实现方法如下: #include <iostream> #include <vector> #include <iterator> #include <algorithm> using namespace std; vector<int> result; struct Node { Node(int i = 0, Node *pl