『数据结构』二叉树

树的简介


树是一种非线性结构, 树状结构是结点间有分支的, 层次的结构.

一些基本术语


度数一个结点的子树个数
树叶没有子树的结点称为树叶或终端结点
双亲结点或父节点:若一个结点含有子节点,则这个结点称为子节点的父节点
孩子节点或子节点一个结点含有的子树的根结点称为该节点的子节点
层数:定义树根的层数为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 2K1,则它就是满二叉树。
在这里插入图片描述

完全二叉树


根节点到倒数第二层为满二叉树最后一层可以不完全填满,叶子结点都靠左对齐
在这里插入图片描述

二叉树的存储结构


二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构

  • 顺序存储:顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实使用中只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一棵二叉树
  • 链式存储:二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该节点左右孩子所在的结点的存储地址。链式结构分为二叉链和三叉链

在这里插入图片描述

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 +
                '}';
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值