树的简介
树是一种非线性结构, 树状结构是结点间有分支的, 层次的结构.
一些基本术语
度数:一个结点的子树个数。
树叶:没有子树的结点称为树叶或终端结点。
双亲结点或父节点:若一个结点含有子节点,则这个结点称为子节点的父节点。
孩子节点或子节点:一个结点含有的子树的根结点称为该节点的子节点。
层数:定义树根的层数为1,其他结点的层数等于其父母结点的层数加1。
高度或深度:树中结点的最大层数,规定空树的高度为0。
树的表示
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如:双亲表示法,孩子表示法,孩子兄弟表示法等等。我们这里就简单的了解其中最常用的孩子兄弟表示法。
typedef int ElementType;
typedef struct Node {
/*---数据域---*/
ElementType value;
/*---第一个孩子结点---*/
struct Node* firstchild;
/*---下一个兄弟结点---*/
struct Node* nextchild;
} Node;
二叉树概念及结构
二叉树是树状结构的另一个重要类型。二叉树的每个结点至多有两个孩子结点,而且孩子结点有左右之分。二叉树的存储结构简单,存储效率较高,树运算的算法实现也相对简单。二叉树还可用来表示树,二叉树在数据结构中有着重要的地位。
二叉树的五种基本形态
特殊的二叉树
满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是
2
K
−
1
2^K - 1
2K−1,则它就是满二叉树。
完全二叉树
从根节点到倒数第二层为满二叉树,最后一层可以不完全填满,叶子结点都靠左对齐。
二叉树的存储结构
二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。
- 顺序存储:顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实使用中只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一棵二叉树。
- 链式存储:二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该节点左右孩子所在的结点的存储地址。链式结构分为二叉链和三叉链。
typedef int ElementType;
/*---二叉链---*/
typedef struct Node {
struct Node* left;
struct Node* right;
ElementType value;
} Node;
/*---三叉链---*/
typedef struct Node {
struct Node* parent;
struct Node* left;
struct Node* right;
ElementType value;
} Node;
二叉树接口实现
C语言版
binary_tree.h:
#pragma once
typedef char ElementType;
/*---结点---*/
typedef struct Node {
ElementType value;
struct Node* left;
struct Node* right;
} Node;
/*---前序创建树---*/
Node* btCreatePre(ElementType preorder[],
int size, int* used);
/*---前序和中序创建树---*/
Node* btCreatePreAndIn(ElementType preorder[],
ElementType inorder[], int size);
/*---中序和后序创建树---*/
Node* btCreateInAndPost(ElementType inorder[],
ElementType postorder[], int size);
/*---前序遍历---*/
void btPreOrder(Node* root);
/*---中序遍历---*/
void btInOrder(Node* root);
/*---后序遍历---*/
void btPostOrder(Node* root);
/*---结点数---*/
size_t btSize(const Node* root);
/*---叶子数---*/
size_t btLeafSize(const Node* root);
/*---树高---*/
size_t btHeight(const Node* root);
/*---K层数量---*/
size_t btKthLevelSize(const Node* root, size_t k);
/*---查找---*/
const Node* btFind(const Node* root, ElementType v);
/*---相同---*/
bool btSame(const Node* root1, const Node* root2);
/*---镜像---*/
bool btMirror(const Node* root1, const Node* root2);
/*---测试---*/
void btTest();
binary_tree.c:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>
#include "binary_tree.h"
Node* btCreatePre(ElementType preorder[],
int size, int* used){
if (size == 0){
*used = 0;
return NULL;
}
if (preorder[0] == '#'){
*used = 1;
return NULL;
}
Node* root = (Node*)malloc(sizeof(Node));
assert(root != NULL);
root->value = preorder[0];
int left_used;
root->left = btCreatePre(preorder + 1, size - 1, &left_used);
int right_used;
root->right = btCreatePre(preorder + 1 + left_used,
size - 1 - left_used, &right_used);
*used = left_used + right_used + 1;
return root;
}
static int eleFind(ElementType inorder[], ElementType ele, int size){
int i = 0;
for (i = 0; i < size; ++i){
if (inorder[i] == ele){
return i;
}
}
return -1;
}
Node* btCreatePreAndIn(ElementType preorder[],
ElementType inorder[], int size){
if (size == 0){
return NULL;
}
ElementType root_value = preorder[0];
int left_size = eleFind(inorder, root_value, size);
Node* root = (Node*)malloc(sizeof(Node));
root->value = root_value;
root->left = btCreatePreAndIn(preorder + 1, inorder, left_size);
root->right = btCreatePreAndIn(preorder + 1 + left_size,
inorder + 1 + left_size, size - 1 - left_size);
return root;
}
Node* btCreateInAndPost(ElementType inorder[],
ElementType postorder[], int size){
if (size == 0){
return NULL;
}
ElementType root_value = postorder[size - 1];
int left_size = eleFind(inorder, root_value, size);
Node* root = (Node*)malloc(sizeof(Node));
assert(root != NULL);
root->value = root_value;
root->left = btCreateInAndPost(inorder, postorder, left_size);
root->right = btCreateInAndPost(inorder + left_size + 1,
postorder + left_size, size - left_size - 1);
return root;
}
void btPreOrder(Node* root){
if (root == NULL){
return;
}
printf("%c ", root->value);
btPreOrder(root->left);
btPreOrder(root->right);
}
void btInOrder(Node* root){
if (root == NULL){
return;
}
btInOrder(root->left);
printf("%c ", root->value);
btInOrder(root->right);
}
void btPostOrder(Node* root){
if (root == NULL){
return;
}
btPostOrder(root->left);
btPostOrder(root->right);
printf("%c ", root->value);
}
size_t btSize(const Node* root){
if (root == NULL){
return 0;
}
size_t left = btSize(root->left);
size_t right = btSize(root->right);
return left + right + 1;
}
size_t btLeafSize(const Node* root){
if (root == NULL){
return 0;
}
if (root->left == NULL && root->right == NULL){
return 1;
}
size_t left = btLeafSize(root->left);
size_t right = btLeafSize(root->right);
return left + right;
}
size_t btHeight(const Node* root){
if (root == NULL){
return 0;
}
size_t left = btHeight(root->left) + 1;
size_t right = btHeight(root->right) + 1;
return left > right ? left : right;
}
size_t btKthLevelSize(const Node* root, size_t k){
if (root == NULL){
return 0;
}
if (k == 1){
return 1;
}
size_t left = btKthLevelSize(root->left, k - 1);
size_t right = btKthLevelSize(root->right, k - 1);
return left + right;
}
const Node* btFind(const Node* root, ElementType v){
if (root == NULL){
return NULL;
}
if (root->value == v){
return root;
}
const Node* temp = btFind(root->left, v);
if (temp != NULL){
return temp;
}
temp = btFind(root->right, v);
if (temp != NULL){
return temp;
}
return NULL;
}
bool btSame(const Node* root1, const Node* root2){
if (root1 == NULL && root2 == NULL){
return true;
}
if (root1 == NULL || root2 == NULL){
return false;
}
return root1->value == root2->value &&
btSame(root1->left, root2->left) &&
btSame(root1->right, root2->right);
}
bool btMirror(const Node* root1, const Node* root2){
if (root1 == NULL && root2 == NULL){
return true;
}
if (root1 == NULL || root2 == NULL){
return false;
}
return root1->value == root2->value &&
btMirror(root1->left, root2->right) &&
btMirror(root1->right, root2->left);
}
void btTest(){
char* preorder = "ABDF####C#E#G";
int size = strlen(preorder);
int used;
Node* root = btCreatePre(preorder, size, &used);
printf("The Binary Tree's PreOrder is: ");
btPreOrder(root);
printf("\n");
size_t num = btSize(root);
printf("The Binary Tree has %lu nodes!\n", num);
size_t leaf_num = btLeafSize(root);
printf("The Binary Tree has %lu leaf nodes!\n", leaf_num);
size_t height = btHeight(root);
printf("The Binary Tree's Height is: %lu!\n", height);
const Node* node = btFind(root, 'A');
printf("root->value: %c, root->left: %c, root->right: %c\n",
node->value, node->left->value, node->right->value);
}
Java版
import java.util.LinkedList;
import java.util.Queue;
public class BinaryTree {
public static void main(String[] args) {
String pre = "ABD##EG###C#F##";
TreeNode root = buildTreeByPre(pre);
System.out.println(isCompleteTree(root));
}
// 判断一棵树是不是完全二叉树
public static boolean isCompleteTree(TreeNode root) {
if (root == null) {
return true;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean flag = false;
while (!queue.isEmpty()) {
TreeNode curNode = queue.poll();
if (curNode == null) {
flag = true;
continue;
}
if (flag) {
return false;
}
queue.offer(curNode.left);
queue.offer(curNode.right);
}
return true;
}
// 层序遍历
public static void levelOrder(TreeNode root) {
if (root == null) {
return;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int qSize = queue.size();
for (int i = 0; i < qSize; ++i) {
TreeNode curNode = queue.poll();
System.out.print(curNode.val + " ");
if (curNode.left != null) {
queue.offer(curNode.left);
}
if (curNode.right != null) {
queue.offer(curNode.right);
}
}
System.out.println();
}
}
// 按值查找结点
public static TreeNode find(TreeNode root, int val) {
if (root == null) {
return null;
}
if (root.val == val) {
return root;
}
TreeNode ret = find(root.left, val);
return ret != null ? ret : find(root.right, val);
}
// 求第K层结点数
public static int kLevelNodeSize(TreeNode root, int k) {
if (root == null || k <= 0) {
return 0;
}
if (k == 1) {
return 1;
}
return kLevelNodeSize(root.left, k - 1) + kLevelNodeSize(root.right, k - 1);
}
// 求叶子结点个数
public static int leafNodeSize(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
return leafNodeSize(root.left) + leafNodeSize(root.right);
}
// 求结点个数
public static int nodeSize(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
return 1 + nodeSize(root.left) + nodeSize(root.right);
}
// 后序遍历
public static void postOrder(TreeNode root) {
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
// 中序遍历
public static void inOrder(TreeNode root) {
if (root == null) {
return;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
// 前序遍历
public static void preOrder(TreeNode root) {
if (root == null) {
return;
}
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
// 根据前序构建树
private static int index = 0;
public static TreeNode buildTreeByPre(String pre) {
char ch = pre.charAt(index);
if (ch == '#') {
return null;
}
TreeNode root = new TreeNode(ch);
++index;
root.left = buildTreeByPre(pre);
++index;
root.right = buildTreeByPre(pre);
return root;
}
}
class TreeNode {
public char val;
public TreeNode left = null;
public TreeNode right = null;
public TreeNode(char val) {
this.val = val;
}
@Override
public String toString() {
return "TreeNode{" +
"val=" + val +
'}';
}
}