树形结构应该是贯穿整个数据结构的一个比较重要的一种结构,它的重要性不言而喻!

讲到树!一般都是讨论二叉树,而关于二叉树的定义以及概念这里不做陈诉,可自行搜索。

在C语言里面需要实现一个二叉树,我们需要申明一个结构体,而关于其结构体的多种方法

这里也不一一列出,我采用比较通用的方法:

struct TreeNode{

ElementType Element;

struct TreeNode *Left;

struct TreeNode *RIght;

};

BinaryTree.h:

#ifndef TREE_H
#define TREE_H typedef char TreeElementType; typedef struct TreeNode *PtrToNode;
typedef PtrToNode BinTree; struct TreeNode
{
TreeElementType Element;
struct TreeNode *Left;
struct TreeNode *Right;
}; BinTree CreateTree();//先序遍历创建二叉树
BinTree IterationCreateTree();//先序非递归创建二叉树 void PreOrderTraversal(BinTree BT);
void IterationPreOrderTraversal(BinTree BT); void InOrderTraversal(BinTree BT);
void IterationInOrderTraversal(BinTree BT); void PostOrderTraversal(BinTree BT);
void IterationPostOrderTraversal(BinTree BT); void LevelTraversal(BinTree BT); int SumNode(BinTree BT);
int SumLeafNode(BinTree BT);
int Depth(BinTree BT);//输出整个二叉树的深度 #endif

整个关于二叉树的操作函数都写了它的递归和迭代版本(层次遍历没有写递归版本),为了保持文件的封装性,将整个关于二叉树的简单操作都封装在一个.c文件里

TreeOperate.c:

#include"BinaryTree.h"
#include"Stack.c"
#include"Queue.c"
#include<stdio.h>
#include<stdlib.h> #define MaxSize 50//栈和队列的大小 //先序递归创建二叉树
BinTree CreateTree()
{
TreeElementType ch;
BinTree BT;
ch = getchar();
if(ch == '')
BT = NULL;
else
{
BT = (BinTree)malloc(sizeof(struct TreeNode));
if(NULL == BT)
{
printf("Out of space!!!");
return NULL;
}
BT->Element = ch;
BT->Left = CreateTree();
BT->Right = CreateTree();
}
return BT;
} void PreOrderTraversal(BinTree BT)
{
if(BT)
{
printf("%c ", BT->Element);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
} void InOrderTraversal(BinTree BT)
{
if(BT)
{
InOrderTraversal(BT->Left);
printf("%c ", BT->Element);
InOrderTraversal(BT->Right);
}
} void PostOrderTraversal(BinTree BT)
{
if(BT)
{
PostOrderTraversal(BT->Left);
PostOrderTraversal(BT->Right);
printf("%c ", BT->Element);
}
} /*-------------------下面是非递归写法------------------------*/
//先序非递归创建二叉树
BinTree IterationCreateTree()
{
int Flag[MaxSize] = {};
Stack S;
S = CreatStack(MaxSize);
TreeElementType ch;
BinTree Root;
PtrToNode NewCell, T;
printf("请输入简单二叉树的元素类似:222003004500600:\n");
do{
ch = getchar();
if(ch == '')
NewCell = NULL;
else
{
NewCell = (BinTree)malloc(sizeof(struct TreeNode));
if(NULL == NewCell)
{
printf("Alloc is fairure!!");
return NULL;
}
else
{
NewCell->Element = ch;
NewCell->Left = NewCell->Right = NULL;
}
}
//根节点入栈
if(IsEmpty(S) && NewCell)
{
Push(S, NewCell);
Root = NewCell;//第一个进栈的为根节点
Flag[S->TopOfStack] = ;
}
//如果当前(栈顶)节点已经连接左节点,现在连接右节点
else if(Flag[S->TopOfStack] == )
{
T = TopAndPop(S);
T->Right = NewCell;
if(NewCell)
{
Push(S, NewCell);
Flag[S->TopOfStack] = ;//元素进栈后都要置为0,清除隐患
}
}
//该左孩子节点入栈,并连接父亲节点
else
{
Flag[S->TopOfStack] = ;//父亲结点标记为1,表示已经连接左结点
//下面是连接左结点的代码
T = Top(S);
T->Left = NewCell;
if(NewCell)
{
Push(S, NewCell);
Flag[S->TopOfStack] = ;//元素进栈后都要置为0,清除隐患
}
}
}while(!IsEmpty(S)); return Root;
}
//先序
void IterationPreOrderTraversal(BinTree BT)
{
Stack S;
S = CreatStack(MaxSize);
BinTree T = BT;
while(T || !IsEmpty(S))
{
while(T)
{
Push(S, T);
//注意printf的顺序,因为他是在访问左孩子节点时就已经处理了!
printf("%c ", T->Element);
T = T->Left;
}
if(T == NULL)
{
T = TopAndPop(S);
T = T->Right;
}
}
}
//中序
void IterationInOrderTraversal(BinTree BT)
{
Stack S;
S = CreatStack(MaxSize);
BinTree T = BT;
while(T || !IsEmpty(S))
{
while(T)
{
Push(S, T);
T = T->Left;
}
if(T == NULL)
{
T = TopAndPop(S);
//printf在访问右孩子之前就处理的当前元素
printf("%c ", T->Element);
T = T->Right;
}
}
}
//后序
//void IterationPostOrderTraversal(BinTree BT)
//{
// int Flag[MaxSize];
// Stack S;
// S = CreatStack(MaxSize);
// BinTree T = BT;
// while(T || !IsEmpty(S))
// {
// while(T)
// {
// Push(S, T);
// Flag[S->TopOfStack] = 0;//未处理的标记为0
// T = T->Left;
// }
// while(Flag[S->TopOfStack] == 1)
// {
// T = TopAndPop(S);
// printf("%c ", T->Element);
// T = NULL;//该节点被处理后,父亲节点的右孩子置空
// }
// if(!IsEmpty(S))
// {
// T = Top(S);
// T = T->Right;
// Flag[S->TopOfStack] = 1;
// }
// }
//}
//第二种版本
void IterationPostOrderTraversal(BinTree BT)
{
int Flag[MaxSize] = {};
Stack S;
S = CreatStack(MaxSize);
BinTree T = BT;
while(T || !IsEmpty(S))
{
/*将左结点全部入栈*/
if(T)
{
Push(S, T);
Flag[S->TopOfStack] = ;//未处理的标记为0
T = T->Left;
}
/*如果已经访问了该结点的右孩子,将它出队并打印*/
else if(Flag[S->TopOfStack] == )
{
T = TopAndPop(S);
printf("%c ", T->Element);
T = NULL;//该节点被处理后置空,否则会被识别入栈
}
/*如果左孩子为空,则访问它的右孩子*/
else
{
T = Top(S);
T = T->Right;
Flag[S->TopOfStack] = ;//访问了右孩子,标记为1
}
}
}
//层次
void LevelTraversal(BinTree BT)
{
Queue Q;
Q = CreatQueue(MaxSize);
BinTree T = BT;
Enqueue(Q, T);
while(!QIsEmpty(Q))
{
T = FrontAndDequeue(Q);
printf("%c ", T->Element);
if(T->Left)
Enqueue(Q, T->Left);
if(T->Right)
Enqueue(Q, T->Right);
}
} int SumNode(BinTree BT)
{
if(NULL == BT)
return ;
else if(BT->Left == NULL && BT->Right == NULL)
return ;
else
return SumNode(BT->Left) + SumNode(BT->Right) + ;//加1等于是每次返回 加一个根结点
} int SumLeafNode(BinTree BT)
{
if(NULL == BT)
return ;
else if(BT->Left == NULL && BT->Right == NULL)
return ;
else
return SumLeafNode(BT->Left) + SumLeafNode(BT->Right);
} int Depth(BinTree BT)//输出的是整个二叉树的深度
{
int DepthOfLeft = ;
int DepthOfRight = ;
if(NULL == BT)
return ;
else
{
DepthOfLeft = Depth(BT->Left);
DepthOfRight = Depth(BT->Right);
return (DepthOfLeft > DepthOfRight) ? DepthOfLeft + : DepthOfRight + ;
}
}

上文用到的栈的操作和队列的操作出自https://www.cnblogs.com/Crel-Devi/p/9460945.html和https://www.cnblogs.com/Crel-Devi/p/9600940.html,需修改栈和队列同名的函数名称以及Element的名字以及栈和队列的元素类型!!!!!!!(非常重要)

下面给出一个简单的测试代码main.c:

#include"BinaryTree.h"
#include<stdio.h>
#include<stdlib.h> /* run this program using the console pauser or add your own getch, system("pause") or input loop */ int main(int argc, char *argv[]) {
BinTree BT;
printf("请输入二叉树的元素:");
BT = CreateTree();
//BT = IterationCreateTree(); printf("先序遍历(递归):\t");
PreOrderTraversal(BT);
printf("\n");
printf("先序遍历(迭代):\t");
IterationPreOrderTraversal(BT);
printf("\n\n"); printf("中序遍历(递归):\t");
InOrderTraversal(BT);
printf("\n");
printf("中序遍历(迭代):\t");
IterationInOrderTraversal(BT);
printf("\n\n"); printf("后序遍历(递归):\t");
PostOrderTraversal(BT);
printf("\n");
printf("后序遍历(迭代):\t");
IterationPostOrderTraversal(BT);
printf("\n\n"); printf("层次遍历(迭代):\t");
LevelTraversal(BT);
printf("\n\n"); int allnode, leafnode, treedepth;
allnode = SumNode(BT);
leafnode = SumLeafNode(BT);
treedepth = Depth(BT);
printf("二叉树结点总数:%d\t\n", allnode);
printf("二叉树叶节点总数:%d\t\n", leafnode);
printf("二叉树深度:%d\t\n", treedepth);//输出整棵树的深度
printf("\n"); return ;
}

二叉树的简单操作(Binary Tree)的更多相关文章

  1. [Swift]LeetCode144. 二叉树的前序遍历 | Binary Tree Preorder Traversal

    Given a binary tree, return the preorder traversal of its nodes' values. Example: Input: [1,null,2,3 ...

  2. (二叉树 递归) leetcode 144. Binary Tree Preorder Traversal

    Given a binary tree, return the preorder traversal of its nodes' values. Example: Input: [1,null,2,3 ...

  3. 二叉树叶子顺序遍历 · binary tree leaves order traversal

    [抄题]: 给定一个二叉树,像这样收集树节点:收集并移除所有叶子,重复,直到树为空. 给出一个二叉树: 1 / \ 2 3 / \ 4 5 返回 [[4, 5, 3], [2], [1]]. [暴力解 ...

  4. LeetCode 144. 二叉树的前序遍历(Binary Tree Preorder Traversal)

    144. 二叉树的前序遍历 144. Binary Tree Preorder Traversal 题目描述 给定一个二叉树,返回它的 前序 遍历. LeetCode144. Binary Tree ...

  5. (二叉树 BFS) leetcode 107. Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  6. [Swift]LeetCode156.二叉树的上下颠倒 $ Binary Tree Upside Down

    Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that ...

  7. [Swift]LeetCode102. 二叉树的层次遍历 | Binary Tree Level Order Traversal

    Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, ...

  8. [Swift]LeetCode199. 二叉树的右视图 | Binary Tree Right Side View

    Given a binary tree, imagine yourself standing on the right side of it, return the values of the nod ...

  9. [Swift]LeetCode257. 二叉树的所有路径 | Binary Tree Paths

    Given a binary tree, return all root-to-leaf paths. Note: A leaf is a node with no children. Example ...

随机推荐

  1. day10函数,函数的使用,函数的分类,函数的返回值

    函数 # ***** # 函数:完成 特定 功能的代码块,作为一个整体,对其进行特定的命名,该名字就代表函数 # -- 现实中:很多问题要通过一些工具进行处理 => 可以将工具提前生产出来并命名 ...

  2. 20175312 2018-2019-2 《Java程序设计》第7周学习总结

    20175312 2018-2019-2 <Java程序设计>第7周学习总结 教材学习内容总结 已依照蓝墨云班课的要求完成了第八章的学习,主要的学习渠道是PPT,和书的课后习题. 总结如下 ...

  3. 论文笔记:Learning regression and verification networks for long-term visual tracking

    Learning regression and verification networks for long-term visual tracking 2019-02-18 22:12:25 Pape ...

  4. Java基本语法(一)

    1,Java中命名规则与规范 命名规则是我们必须遵守的约定: 1,Java中需要命名的地方(我们称之为标识符),可以26个英文字母(不区分大小写),0-9的数字,_和$等组成,不能包含特殊字符(#), ...

  5. [评测]低配环境下,PostgresQL和Mysql读写性能简单对比(欢迎大家提出Mysql优化意见)

    [评测]低配环境下,PostgresQL和Mysql读写性能简单对比 原文链接:https://www.cnblogs.com/blog5277/p/10658426.html 原文作者:博客园--曲 ...

  6. canvas 模拟时钟

    <meta charset="utf-8"> <canvas width="1000" height="1000" id= ...

  7. 牛客 黑龙江大学程序设计竞赛重现 19-4-25 D

    题意: n项工作 1~n  工时s[i] ~e[i], 工时有覆盖的工作不能被同一台机器同时操作, 问完成所有工作的最少机器数 思路:前缀差分和 e.g. a            2 3 4    ...

  8. MPU6050可以读取器件ID值,但读出的加速度计和陀螺仪的数据均为零

    今天在调试MPU6050时发现,MPU6050可以正常读取器件ID,但读取的加速度计和陀螺仪的数据均为零. 经过排查发现,MPU6050第20脚的电容没用焊接,C6可以使用10uF的电容.

  9. 记一次webpack4.x项目配置

    在自构建自己的个人页面的时候使用到webpack4,遇到了一些问题,查看了大佬们的文章以及官方文档,在这里总结一下. webpack比较基础的东西就不赘述了,代码里面的注释也会辅助说明,先看一下目录结 ...

  10. android -------- Hawk数据库

    Hawk 是一个非常便捷的数据库  . 操作数据库只需一行代码 , 能存任何数据类型 . github 地址: https://github.com/orhanobut/hawk 一.概念 Share ...