一、顺序存储
顺序存储是一个让人又爱又恨的玩意儿。爱是因为它理解起来比较简单,查找起来也比较方便;恨是因为这玩意儿太傻瓜,它只一次性地问内存要一段连续的空间,而且坚决不管在实际应用中够用不够用,而且这货在插入和删除元素时居然需要O(n^2)的时间复杂度,这个让人有点无语。那二叉树的顺序存储怎么样呢?让我们来分析分析。
1.比如说我有一棵完全二叉树,如图1(a)所示。该二叉树中有6个元素,可以将这六个元素按照层次从上到下,每一层从左到右的规则依次放入一个数组中,如图1(b)所示。除了数组的内存空间的问题外,这个看起来还过得去。但是,悲剧就要来了...
2.比如说,我有一棵一般二叉树,这棵二叉树只有四个结点(A/B/C/D),A拥有左右子树B/C,B是光棍没有孩子,C计划生育贯彻得好,仅有一个孩子D。但是为了能够方便地从双亲找到孩子(或者从孩子找到双亲)(关于双亲与孩子的关系,请参见数据结构之树的基本术语与性质总结),需要构建一些“虚结点”,从而使得一般二叉树“虚化”为完全二叉树,如图2(a)所示,B的两个孩子就是虚结点。然后按照完全二叉树的顺序存储方式进行存储,存储结果如图2(b)所示,数组中脚标为3的位置存放B的左子树,由于是虚结点,所以为空;脚标为4的位置存放B的右子树,同样因为是虚结点,所以为空。可以看出,对于一般二叉树,如果虚结点过多的话,数组中会有很多的空值,贼浪费空间。当然,如果您还觉得这样能过得去的话,让我们看看下面的退化二叉树吧,纯属洗脑了。
3.现在来演示一下万恶的退化二叉树,如图3(a)所示,该二叉树深度为3,但是恶心的地方到了,总共的元素个数也为3,这样,如果按照2中的方式顺序存储的话,数组中势必会有更多的元素为空。随着二叉树层数的增多,空元素是以指数级在增长的。如果这样的话,该会浪费多少内存空间啊,太可怕了。
当然,没有解决不了的问题,链式存储就是解决该问题的神器!
二、链式存储
链式存储的结构分为两种:二叉链表结构和三叉链表结构。
1.二叉链表结构
一个二叉链表结点由三部分组成:数据域,左孩子指针和右孩子指针,如下图所示。
其中,数据域data用来存放结点信息,左孩子指针lchild用来指向该结点的左子树,右孩子指针rchild用来指向该结点的右子树。图4(a)所示的完全二叉树的二叉链表结构如图4(b)所示。
2.三叉链表结构
三叉链表结点是在二叉链表结点的基础上,增加了一个指向双亲结点的指针域,如下图所示。
其中,data表示二叉树结点的数据域内容,lchild指向该结点的左孩子,rchild指向该结点的右孩子,parent指向该结点的双亲结点。图5(a)所示的完全二叉树的三叉链表结构如图5(b)所示。
三、比较
1.顺序存储与链式存储比较
(a)顺序存储分配的内存空间大小是固定的,不好根据二叉树结点数目的增多而动态扩展。如果内存空间分配过大,势必造成内存空间的浪费;如果分配过小,则会产生数组溢出的问题。另外,顺序存储在增加和删除结点时时间复杂度为O(n^2)。顺序存储的好处是方便查找结点。
(b)链式存储可以动态分配内存空间,比顺序存储更加灵活、方便,结点的最大数目仅与系统存储空间相关。另外,在插入/删除结点时的时间复杂度仅为O(n)。因此,在对二叉树操作时更多采用链式存储结构。
2.二叉链表与三叉链表
三叉链表结点比二叉链表结点多了一个指向双亲结点的指针,因此增加了空间开销。但是,三叉链表的好处是既可以查找孩子结点,也可以查找双亲结点,在需要频繁查找双亲结点的应用中更为方便。
二叉树的顺序存储
于 2022-04-15 00:27:56 首次发布
本文探讨了二叉树的顺序存储和链式存储两种方法。顺序存储简单易懂,但面临空间浪费和高时间复杂度问题,特别是对于非完全二叉树和退化二叉树。链式存储,包括二叉链表和三叉链表,解决了动态扩展和效率问题,但额外增加了空间开销。三叉链表在需要频繁查找双亲结点时更具优势。
摘要由CSDN通过智能技术生成