`

大话数据结构十三:二叉树的链式存储结构(二叉链表)

 
阅读更多

1. 关于树

树的度也即是宽度,简单地说,就是结点的分支数。

树的深度 — 组成该树各结点的最大层次

森林 — 指若干棵互不相交的树的集合

有序树 — 指树中同层结点从左到右有次序排列,它们之间的次序不能互换,这样的树称为有序树,否则称为无序树


2. 二叉树的特点

i、每个结点最多有两颗子树

ii、左子树和右子树是有顺序的,次序不能任意颠倒

iii、即使树中某结点只有一颗子树,也要区分它是左子树还是右子树


3. 二叉树五种形态

① 空二叉树

只有一个根结点

根结点只有左子树

④ 根结点只有右子树

⑤ 根结点既有左子树又有右子树




4. 特殊的二叉树

① 斜树:所有的结点都只有左子树的二叉树叫左斜树,所有的结点都只有右子树的二叉树叫右斜树,这两者统称为斜树。



② 满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。



③ 完全二叉树:对一棵具有n个结点的二叉树按层序编号,如果编号为i (1<=i<=n) 的结点与同样深度的满二叉树中编号为i的结点位置完全相同,则这棵二叉树称为完全二叉树。




下图中不是完全二叉树,因为5没有左右子树,导致8,9,C,D,E,F 中间没有连续:




5. 二叉树的转换

将树转换为二叉树的步骤如下:

① 加线:所有兄弟节点之间加线

② 去线:保留树中每个结点与它第一个孩子的连线,删除其与其他孩子的连线

③ 层次调整:以根结点为轴心,将整棵树旋转,使之层次分明。



6. 二叉树的遍历(Java实现)

① 前序遍历:先访问根节点,再访问左子树,最后访问右子树。

② 中序遍历:先访问左子树,再访问根节点,最后访问右子树。

③ 后序遍历:先访问左子树,再访问右子树,最后访问根节点。

④ 层序遍历:从树的根结点开始,从上向下逐层访问,在同一层中,先左后右逐个访问。


public class LinkedBinaryTree {

	private Node root; // 根节点

	/**
	 * 内部节点类
	 */
	private class Node {
		private Node leftChild; // 左子节点
		private Node rightChild; // 右子节点
		private int data;

		public Node(int data) {
			this.leftChild = null;
			this.rightChild = null;
			this.data = data;
		}
	}

	public LinkedBinaryTree() {
		root = null;
	}

	/**
	 * 递归创建二叉树
	 * 
	 * @param node
	 * @param data
	 */
	public void buildTree(Node node, int data) {
		if (root == null) {
			root = new Node(data);
		} else {
			if (data < node.data) {
				if (node.leftChild == null) {
					node.leftChild = new Node(data);
				} else {
					buildTree(node.leftChild, data); // 递归遍历左子树
				}
			} else {
				if (node.rightChild == null) {
					node.rightChild = new Node(data);
				} else {
					buildTree(node.rightChild, data); // 递归遍历右子树
				}
			}
		}
	}

	/**
	 * 前序遍历(递归实现)
	 * 
	 * @param node
	 */
	public void preOrderTraverse(Node node) {
		if (node != null) {
			System.out.print(" " + node.data + " ");
			preOrderTraverse(node.leftChild);
			preOrderTraverse(node.rightChild);
		}
	}

	/**
	 * 中序遍历(递归实现)
	 * 
	 * @param node
	 */
	public void inOrderTraverse(Node node) {
		if (node != null) {
			inOrderTraverse(node.leftChild);
			System.out.print(" " + node.data + " ");
			inOrderTraverse(node.rightChild);
		}
	}

	/**
	 * 后序遍历(递归实现)
	 * 
	 * @param node
	 */
	public void postOrderTraverse(Node node) {
		if (node != null) {
			postOrderTraverse(node.leftChild);
			postOrderTraverse(node.rightChild);
			System.out.print(" " + node.data + " ");
		}
	}

	/**
	 * 前序遍历(非递归实现)
	 * 
	 * @param node
	 */
	public void preOrderTraverseNoRecursion(Node node) {
		Stack<Node> stack = new Stack<Node>();
		if (node != null) {
			stack.push(node); // 元素进栈
			while (!stack.isEmpty()) {
				node = stack.pop(); // 栈顶元素出栈
				System.out.print(" " + node.data + " ");
				if (node.rightChild != null)
					stack.push(node.rightChild);
				if (node.leftChild != null)
					stack.push(node.leftChild);
			}
		}
	}

	/**
	 * 中序遍历(非递归实现)
	 * 
	 * @param node
	 */
	public void inOrderTraverseNoRecursion(Node node) {
		Stack<Node> stack = new Stack<Node>();
		while ((node != null) || (!stack.isEmpty())) {
			if (node != null) {
				stack.push(node);
				node = node.leftChild;
			} else {
				node = stack.pop();
				System.out.print(" " + node.data + " ");
				node = node.rightChild;
			}
		}
	}

	/**
	 * 后序遍历(非递归实现)
	 * 
	 * @param node
	 */
	public void postOrderTraverseNoRecursion(Node node) {
		Stack<Node> stack = new Stack<Node>();
		Node preNode = null;
		if (node != null) {
			stack.push(node);
			while (!stack.isEmpty()) {
				node = stack.peek();
				if ((node.leftChild == null && node.rightChild == null) 
						|| (preNode != null && (preNode == node.leftChild || preNode == node.rightChild))) {
					System.out.print(" " + node.data + " ");
					stack.pop();
					preNode = node;
				} else {
					if (node.rightChild != null)
						stack.push(node.rightChild);
					if (node.leftChild != null)
						stack.push(node.leftChild);
				}
			}
		}
	}

	/**
	 * 层序遍历(非递归实现)
	 * 
	 * @param node
	 */
	public void levelOrderTraverse(Node node) {
		Queue<Node> queue = new LinkedList<Node>();
		if (node != null) {
			queue.offer(node); // 将元素插入队列
			while (!queue.isEmpty()) {
				node = queue.poll(); // 队列头部出列
				System.out.print(" " + node.data + " ");
				if (node.leftChild != null)
					queue.offer(node.leftChild);
				if (node.rightChild != null)
					queue.offer(node.rightChild);
			}
		}
	}

	/**
	 * 测试方法
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		int[] arr = { 6, 4, 8, 1, 7, 3, 9, 2, 5 };
		LinkedBinaryTree bTree = new LinkedBinaryTree();

		// 构建一棵二叉树
		for (int i = 0; i < arr.length; i++) {
			bTree.buildTree(bTree.root, arr[i]);
		}
		bTree.preOrderTraverse(bTree.root); // 前序遍历(递归)
		bTree.inOrderTraverse(bTree.root); // 中序遍历(递归)
		bTree.postOrderTraverse(bTree.root); // 后序遍历(递归)
		bTree.preOrderTraverseNoRecursion(bTree.root); // 前序遍历(非递归)
		bTree.inOrderTraverseNoRecursion(bTree.root); // 中序遍历(非递归)
		bTree.postOrderTraverseNoRecursion(bTree.root); // 后序遍历(非递归)
		bTree.levelOrderTraverse(bTree.root); // 层序遍历(非递归)
	}

}
递归创建的二叉树如下图:

打印结果:

①前序遍历(递归) :6 4 1 3 2 5 8 7 9
② 中序遍历(递归) :1 2 3 4 5 6 7 8 9
③ 后序遍历(递归) :2 3 1 5 4 7 9 8 6
④前序遍历(非递归):6 4 1 3 2 5 8 7 9
⑤ 中序遍历(非递归):1 2 3 4 5 6 7 8 9
⑥ 后序遍历(非递归):2 3 1 5 4 7 9 8 6
⑦ 层序遍历(非递归):6 4 8 1 5 7 9 3 2


分享到:
评论

相关推荐

    数据结构课程设计二叉树采用二叉链表作为存储结构

    数据结构课程设计之二叉树采用二叉链表作为存储结构 本课程设计的主要任务是设计并实现一个二叉树的存储结构,使用二叉链表作为存储结构,并实现按层次顺序遍历二叉树的算法。下面是本设计的详细解释和实现过程: ...

    二叉树的链式存储结构-二叉链表

    二叉树是一种重要的数据结构,它在计算机科学中有着广泛的应用,特别是在算法设计、数据库系统、编译器构造等领域。二叉链表是实现二叉树的一种高效存储方式,能够有效地处理二叉树的各种操作,如插入、删除、查找等...

    数据结构第六章课件及建立二叉树的二叉链表存储结构汇总

    本资料集专注于数据结构的第六章内容,特别是关于二叉树及其二叉链表存储结构的讲解。二叉树是一种特殊的树结构,每个节点最多只有两个子节点,通常分为左子节点和右子节点。这种结构广泛应用于搜索、排序、文件系统...

    数据结构 建立二叉树二叉链表存储结构实现有关操作 实验报告

    ### 数据结构:建立二叉树二叉链表存储结构实现有关操作 #### 一、实验题目及背景 本次实验的主要任务是通过建立二叉树的二叉链表存储结构来实现特定的操作。二叉树是一种重要的非线性数据结构,在计算机科学中有...

    数据结构5.8二叉树链式存储-二叉链表

    ### 数据结构5.8二叉树链式存储—二叉链表 #### 一、二叉链表存储结构概述 二叉链表是二叉树的一种常见存储方式,它通过链表来表示二叉树中的节点关系。在二叉链表中,每个节点通常包含三个部分:一个数据域用于...

    数据结构课程设计:二叉树的存储和遍历、排序

    数据结构课程设计:二叉树的存储和遍历、排序 本课程设计主要讨论了二叉树的存储和遍历、排序等内容。二叉树是一种特殊的树结构,每个结点最多有两个子树,通常子树的根被称作“左子树”(left subtree)和“右子树...

    二叉链表作存储结构,设计求二叉树高度的算法

    以二叉链表作存储结构,设计求二叉树高度的算法。

    数据结构实验报告-实现二叉树的基本操作-用顺序存储和链式存储结构

    参考资料:《数据结构》(C语言版)严蔚敏&&吴伟民&&米宁著 要求选用顺序存储结构和二叉链表存储结构实现抽象数据类型二叉树的基本操作。有个亮点是利用字符在dos界面显示二叉树的结构形态。 里面包含了完整的源程序和...

    数据结构5.10二叉树线索链表存储结构

    ### 数据结构5.10二叉树线索链表存储结构 #### 一、知识点概述 在数据结构的学习中,二叉树是一种非常重要的非线性数据结构,它具有丰富的应用场景和变化形式。其中,二叉树的线索链表存储结构是通过对二叉树的...

    二叉树的二叉链表存储表示

    在计算机科学中,二叉树是一种重要的数据结构,它广泛应用于许多领域,如数据库、操作系统、编译器等。二叉树的存储表示是指将二叉树存储在计算机中的一种方式,其中二叉链表存储表示是一种常用的存储方式。 二叉...

    数据结构5.9二叉树的链式存储-三叉链表

    ### 数据结构5.9二叉树的链式存储-三叉链表 #### 一、基础知识概述 在学习三叉链表之前,我们先来回顾一下什么是二叉树以及链式存储的基本概念。 **二叉树**是一种常见的非线性数据结构,其中每个节点最多有两个...

    二叉树的二叉链表源码

    二叉树的二叉链表源码

    先序递归建立二叉树

    用先序递归过程建立二叉树 (存储结构:二叉链表) 输入数据按先序遍历所得序列输入,当某结点左子树或右子树为空时,输入‘*’号

    数据结构实验-二叉树的基本操作

    一、问题描述 运用二叉链表实现二叉树的基本操作,包括:创建二叉树的存储结构、复制...1、构造二叉树的二叉链表数据结构。 2、实现二叉树的创建、复制、计算二叉树的深度、先根序序列、中根序序列、后根序序列等操作。

    用顺序和二叉链表作存储结构实现二叉排序树

    "用顺序和二叉链表作存储结构实现二叉排序树" 本课程设计旨在使用顺序和二叉链表作为存储结构来实现二叉排序树。二叉排序树是一种重要的数据结构,它广泛应用于计算机科学和技术领域。通过本课程设计,我们将学习...

    二叉链表叶子节点的输出

    根据给定的信息,本文将详细解释“二叉链表叶子节点的输出”这一主题,包括相关的数据结构定义、创建二叉树的过程、遍历方法以及如何统计并输出叶子节点的数量。 ### 一、数据结构定义 在C语言中,二叉树通常通过...

    构建二叉树的二叉链表存储结构

    【构建二叉树的二叉链表存储结构】 在计算机科学中,二叉树是一种特殊的树形数据结构,其中每个节点最多有两个子节点,通常分为左子节点和右子节点。二叉链表存储结构是二叉树常用的一种存储方式,它通过节点的数据...

    数据结构源码之二叉树的二叉链表

    本文将详细介绍一个基于C语言实现的二叉树数据结构,该结构采用了二叉链表的形式来存储和管理二叉树中的节点。文章中提供的代码片段涵盖了二叉树的各种基本操作,包括初始化、节点创建、遍历、高度计算、节点插入与...

    链表存储二叉树实验(C语言)

    链表存储二叉树是一种常见的数据结构实现方式,特别是在C语言中,由于其不支持内置的动态数组,链表成为了构建复杂数据结构如二叉树的理想选择。在本实验中,我们将探讨如何使用C语言来实现一个二叉链表表示的二叉树...

    数据结构实验——二叉树

    以二叉链表作存储结构,试编写前序、中序、后序遍历二叉树的算法。

Global site tag (gtag.js) - Google Analytics