精华内容
下载资源
问答
  • 二叉树的作用

    2018-04-16 22:00:00
    二叉树,本质上,是对链表和数组一个折中。。比如,我有一个任务,需要输入 10万个数据(32位整数),然后有两个操作:1.添加(删除)一个整数。2.询问第x大数据。 比如,我给你 1, 8, 13, 10(等等一堆数据)......

    二叉树,本质上,是对链表和数组的一个折中。。
    比如,我有一个任务,需要输入
    10万个数据(32位整数),然后有两个操作:
    1.添加(删除)一个整数。
    2.询问第x大的数据。

    比如,我给你 1, 8, 13, 10(等等一堆数据).......
    然后我询问第3大的数据,
    然后我插入 18
    然后我询问第4大的数据
    我再插入 9
    我再询问第2大的数据

    不停的重复1,2
    重复10万次。。

    应该如何实现。
    你会发现,用有序链表,不行,查找(包括1需要找到对应位置,以及2查找)成本大O(N),但具体这个插入操作成本小O(1)。
    用有序数组,查找(2的查找)成本小O(1)。但1的插入操作成本很大O(N)。

    所以,我们折中使用排序二叉树(二叉树仅仅作为排序二叉树的基础),查找(包括1需要找到对应位置,以及2查找)成本挺小O(logN)。具体这个插入操作成本也挺小O(logN)。

    具体的应用就是由排序二叉树(由于普通排序二叉树可能会有不平衡的情况)引申出来的红黑树(linux中ext3文件系统管理),avl树“windows对进程地址空间的管理”。




    链接:https://www.zhihu.com/question/37381035/answer/84584381
    来源:知乎

    转载于:https://www.cnblogs.com/-1339513141/p/8858841.html

    展开全文
  • 线索二叉树的实现

    2017-09-08 21:40:06
    线索二叉树的作用是为了加快查找结点的前驱和后继的速度 线索二叉树实现的是利用每个结点的空指针(如果有)指向左子树指针指向前一个结点(中序遍历顺序,下同)右子树指向后继结点,但是要添加两个方向指针 LTag, ...
    线索二叉树的作用是为了加快查找结点的前驱和后继的速度
    线索二叉树实现的是利用每个结点的空指针(如果有)指向左子树指针指向前一个结点(中序遍历顺序,下同)右子树指向后继结点,但是要添加两个方向指针

    LTag, RTag,如果LTag = 0,则表示该节点有左孩子,等于1则表示指针为空指向可以指向前驱结点, RTag = 0,则表示该节点有右孩子,等于1则表示指针为空指向可以指向后继结点



    #include <iostream>
    using namespace std;
    
    #define Elemtype char
    
    typedef enum PointerTag
    {
    	Link, Thread
    };
    
    typedef struct BiThrNode
    {
    	Elemtype data;
    	struct BiThrNode *lchild, *rchild;
    	PointerTag LTag, RTag;
    }BiThrNode,*BiThrTree;
    
    BiThrTree Pre = NULL;//全局变量始终指向刚刚经过的结点;
    
    void CreateTree(BiThrTree *T)//先序的方法创造二叉树
    {
    	char ch;
    	scanf_s("%c",&ch);
    
    	if (' ' == ch)
    	{
    		(*T) = NULL;
    	}
    	else
    	{
    		(*T) = new BiThrNode;
    		(*T)->data = ch;
    		(*T)->LTag = Link;
    		(*T)->RTag = Link;
    		CreateTree(&(*T)->lchild);
    		CreateTree(&(*T)->rchild);
    	}
    	
    }
    
    void InThreading(BiThrTree p)//中序遍历线索化
    {
    	if (p)
    	{
    		InThreading(p->lchild);//左子树线索化
    		
    		if (!p->lchild)//如果p的左子树为空即将LTag设置成1,将lchild指向刚刚访问的结点
    		{
    			p->LTag = Thread;
    			p->lchild = Pre;//左子树指向前驱
    		}
    		if (!Pre->rchild)//如果p的右子树为空即将LTag设置成1,表明下一个结点是他的后继
    		{
    			Pre->RTag = Thread;
    			Pre->rchild = p;//右子树指向后继
    		}
    		Pre = p;//保持pre指向p的前驱
    
    		InThreading(p->rchild);//线索化右子树
    	}
    
    }
    
    void InOrderThreading(BiThrTree *Thrt, BiThrTree T)
    {
    	*Thrt = new BiThrNode;//设置一个头结点
    	(*Thrt)->LTag = Link;//头结点的左标志设置成Link证明他有左子树
    	(*Thrt)->RTag = Thread;//头结点的右标志设置成thread证明他有后继结点
    	(*Thrt)->rchild = *Thrt;//开始先让他的右子树指向自己
    
    	if (!T)//若果二叉树是空树就让头结点的左子树指向头结点
    	{
    		(*Thrt)->lchild = *Thrt;
    	}
    	else
    	{
    		(*Thrt)->lchild = T;//如果树不为空,头结点的左子树指向树的根
    		Pre = *Thrt;//pre指向头结点
    		InThreading(T);//开始中序线索化二叉树
    		Pre->rchild = *Thrt;//收尾工作,让二叉树中序遍历的最后一个结点的右子树指向头结点
    		Pre->RTag = Thread;//
    		(*Thrt)->rchild = Pre;//让头结点的右子树指向前一个结点也就是二叉树中序遍历的最后一个结点
    	}
    
    }
    
    void InOrderTraverse(BiThrTree Thrt)//中序遍历线索化二叉树,非递归
    {
    	BiThrTree p;
    	p = Thrt->lchild;//让p 指向树的根结点
    
    	
    	while (p != Thrt)//如果P不等于头结点说明二叉树非空,或者p还没有指向头结点
    	{
    		while (p->LTag == Link)//如果p->LTag == Link说明p一直有右子树,这个操作是为了找出最左边的结点
    		{
    			p = p->lchild;
    		}
    
    		cout << p->data << " ";//输出结点
    
    		while (p->RTag == Thread && p->rchild != Thrt)//p->RTag == Thread && p->rchild != Thrt如果p有后继结点,并且p的右子树还没有指向头结点,就一直按照线索遍历
    		{
    			p = p->rchild;
    			cout << p->data << " ";
    		}
    
    		p = p->rchild;//收尾工作将P再次指向头结点
    	}
    }
    
    int main()
    {
    	char ch;
    	BiThrTree T, Thrt;
    	CreateTree(&T);
    	InOrderThreading(&Thrt, T);
    	InOrderTraverse(Thrt);
    	system("pause");
    	return 0;
    }

    演示结果:


    展开全文
  • 线索二叉树

    2020-12-16 15:32:51
    线索二叉树的作用: (1)将各结点的空指针利用起来; (2)左分支指向其前驱结点,右分支指向其后驱结点;

    线索二叉树的作用:
    (1)将各结点的空指针利用起来;
    (2)左分支指向其前驱结点,右分支指向其后驱结点;

    线索二叉树的代码编写如下:

    1.创建树节点结构,线索二叉树相对于普通的二叉树结点,多了两个标志位lTag和rTag;lTag=1时表明左指针为线索指针,lTag=0时表明左指针为左孩子指针;rTag=1时表明右指针为线索指针,rTag=0时表明左指针为右孩子指针;

    //创建线索树结点
    typedef struct BiThrNode
    {
    	char data;
    	BiThrNode *lchild, *rchild;
    	PointerTag lTag;
    	PointerTag rTag;
    }BiThrNode,*BiThrTree;
    //创建全局变量,指向刚刚访问过的结点
    BiThrTree pre;
    
    1. 采用前序遍历创建树结构
    //创建二叉树,用户遵循前序遍历的规则输入数据
    void CreateBiTree(BiThrTree *T)//这里采用指针的方法进行传入,是为了保证函数中创建的树结构即为主函数中的树结构
    {
    	char c;
    	scanf_s("%c", &c);
    	if (c == ' ')
    		*T = NULL;
    	else
    	{
    		*T = (BiThrNode*)malloc(sizeof(BiThrNode));
    		(*T)->data = c;
    		(*T)->lTag = Link;
    		(*T)->rTag = Link;
    		CreateBiTree(&(*T)->lchild);
    		CreateBiTree(&(*T)->rchild);
    	}
    }
    
    1. 通过增加头结点的方式来创建线索二叉树
    //通过中序遍历将创建的二叉树变为线索二叉树,需要增加头结点的方式
    void inThreading(BiThrTree T)
    {
    	if (T)
    	{
    		inThreading( T->lchild);//左子树线索化
    		if (!T->lchild)
    		{
    			T->lTag = Thread;
    			T->lchild = pre;
    		}
    		else
    			T->lTag = Link;
    		if (!pre->rchild)
    		{
    			pre->rTag = Thread;
    			pre->rchild = T;
    		}
    		else
    			pre->rTag = Link;
    		pre = T;
    		inThreading(T->rchild);//右子树线索化
    	}
    }
    
    1. 采用非递归的方式输出中序线索二叉树的各结点
    //使用非递归的方式(利用线索二叉树的前驱和后继的性质)将树结构以中序遍历顺序输出
    void InOrderTraversePrint(BiThrNode * p)//p为头结点
    {
    	BiThrNode *T = p->lchild;//T指向根节点
    	while (T != p)
    	{
    		while (T->lTag==Link)
    		{
    			T = T->lchild;
    		}
    		visit(T->data);
    		while (T->rTag==Thread && T->rchild != p)
    		{
    			T = T->rchild;
    			visit(T->data);
    		}
    		T = T->rchild;
    	}
    }
    

    5.上述主函数如下

    int main()
    {
    	BiThrTree P, T = NULL;
    	CreateBiTree(&T);
    	InOrderThreading(&P, T);
    	cout << "中序遍历输出结果为: " << endl;
    	InOrderTraversePrint(P);
    	cout << endl;
    	system("pause");
    	return 0;
    }
    }```
    
    
    展开全文
  • 遍历二叉树的作用 基于二叉树的结构, 衍生出了二叉查找树/平衡二叉查找树/堆等等结构或算法(这些之后会讲), 学会如何遍历一颗二叉树是学习此类"派生二叉树"的基础. 二叉树的遍历 我们先来看一颗一般的二叉树. 然后...

    数据结构与算法之二叉树的遍历

    原文来自个人博客(求访问/关注/收藏): https://bbing.com.cn/ CSDN个人博客不定期转载

    遍历二叉树的作用

    基于二叉树的结构, 衍生出了二叉查找树/平衡二叉查找树/堆等等结构或算法(这些之后会讲), 学会如何遍历一颗二叉树是学习此类"派生二叉树"的基础.

    二叉树的遍历

    我们先来看一颗一般的二叉树. 然后根据不同的遍历方式, 看看这颗二叉树结点最终遍历的顺序.
    一般二叉树

    前序遍历

    前序遍历就是按照先根结点, 再左右子结点的方式去遍历(root -> left -> right).

    对一个链式存储的二叉树来说, 代码如下:

    vector<int> pre;
    vector<int> preorderTraversal(TreeNode* root) {
        if (!root)
        {
            return pre;
        }
    
        pre.push_back(root->val);
        preorderTraversal(root->left);
        preorderTraversal(root->right);
    
        return pre;
    }
    

    我们先跟着代码的逻辑走一遍:

    • N1是根结点, push进队列
    [N1]
    
    • 操作N1左子结点N2, N2是N2子树的根结点, push进队列
    [N1, N2]
    
    • 操作N2左子结点N4, N4是N4子树的根结点, push进队列
    [N1, N2, N4]
    
    • N4没有子结点, 操作N4的父结点N2的右子结点N5, N5是N5子树的根结点, push进队列
    [N1, N2, N4, N5]
    
    • 操作N5左子结点N7, N7是N7子树的根结点, push进队列
    [N1, N2, N4, N5, N7]
    
    • N7没有子结点, 退回到父结点, 直到发现N1有右子结点N3, N3是N3子树的根结点, push进队列
    [N1, N2, N4, N5, N7, N3]
    
    • 操作N3左子结点N6, N6是N6子树的根结点, push进队列, 全部遍历完成
    [N1, N2, N4, N5, N7, N3, N6]
    

    所以, 最终按照前序遍历的结果是:

    [N1, N2, N4, N5, N7, N3, N6]
    

    使用递归的编程技巧很容易实现前序遍历的代码, 但是递归有太多的临时变量, 随着递归深度的增加, 消耗的内存也在一直增加;
    (对二叉树这种结构, 递归还可接受, 递归深度一般是logn, 不过极端情况可以达到n)

    如何不使用递归实现前序遍历呢?

    非递归方法实现前序遍历

    这里, 我参考图遍历中一般会用的两个表, OPEN表和CLOSE表实现二叉树的前序遍历, OPEN表和CLOSE表在图论中会讲到.

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> pre;
        if (!root)
        {
            return pre;
        }
    
        stack<TreeNode *> open;
        vector<TreeNode *> close;
    
        auto is_visited = [&] (TreeNode * node) -> bool {
            for (const auto cn : close)
            {
                if (cn == node)
                {
                    return true;
                }
            }
            return false;
        };
    
        open.push(root);
        while(!open.empty())
        {
            TreeNode *top = open.top();
            if (!is_visited(top))
            {
                close.emplace_back(top);
                pre.emplace_back(top->val);
            }
            if (top->left && !is_visited(top->left))
            {
                open.push(top->left);
            }
            else if (top->right && !is_visited(top->right))
            {
                open.push(top->right);
            }
            else
            {
                open.pop();
            }
        }
    
        return pre;
    }
    

    open表中存储了待遍历的结点, close表中存储了已经遍历过的结点. 那么上述代码的大致思想是:

    1. 初始化open表, 将root结点push进表;
    2. 如果open表的top元素没有被遍历过(不在close)表, 这储存其值, 并将top结点加入到close表;
    3. 如果open表的top元素的left结点存在且没有被遍历过, 则将left结点push进open表;
    4. 如果3失败, 但是open表的top元素的right结点存在且没有被遍历过, 则将right结点push进open表;
    5. 如果3/4都失败, 则说明子结点不存在或者都被遍历过, 则弹出top元素;

    中序遍历

    中序遍历就是按照先左子结点, 再根结点, 最后右子结点的方式去遍历(left -> root -> right).

    vector<int> pre;
    vector<int> preorderTraversal(TreeNode* root) {
        if (!root)
        {
            return pre;
        }
    
        preorderTraversal(root->left);
        pre.push_back(root->val);
        preorderTraversal(root->right);
    
        return pre;
    }
    

    中序遍历可以自行思考遍历的过程, 按照中序遍历的结果是:

    [N4, N2, N7, N5, N1, N6, N3]
    

    后序遍历

    后序遍历就是按照先左右子结点, 再根结点的方式去遍历(left -> right -> root).

    vector<int> pre;
    vector<int> preorderTraversal(TreeNode* root) {
        if (!root)
        {
            return pre;
        }
    
        preorderTraversal(root->left);
        preorderTraversal(root->right);
        pre.push_back(root->val);
    
        return pre;
    }
    

    后序遍历可以自行思考遍历的过程, 按照后序遍历的结果是:

    [N4, N7, N5, N2, N6, N3, N1]
    
    展开全文
  • 二叉树

    千次阅读 2017-11-16 15:36:53
    二叉树的好处(应用) 用递归方法建立二叉树 数据结构(六)——二叉树 前序、中序、后序、层次遍历及非递归实现 查找、统计个数、比较、求深度的递归实现 Java中二叉树存储结构实现 二叉树的好处(应用) ...
  • 平衡二叉树

    2018-10-17 22:50:10
    平衡二叉树的作用 解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上...
  • 二叉树的作用:将二叉树线索化后,减少空指针数量,赋予二叉树新的意义。如:在中序线索化后,可以用以近队列存储的方式访问二叉树,加快访问速度和查找效率。 线索化过程: 线索化过程于中序递归遍历没太大区别,先...
  • 数据结构 平衡二叉树

    2021-03-27 19:03:31
    平衡二叉树的基本概念1.1二叉查找树的问题1.2平衡二叉树的概念1.3平衡二叉树的作用2. 平衡二叉树的左旋右旋2.1 左旋或者右旋的触发时机2.2 左旋的过程2.3右旋的过程2.4平衡二叉树旋转的四种情况2.4.1左左2.4.2 左右...
  • 树与二叉树我们生活中大树的感觉,往往给人感觉是靠谱...树的作用和意义:企业的组织架构、决策的过程、族谱图、二叉树可以用来表示算术表达式(赫夫曼编码)。一、数据结构中树的定义:描述:一颗树根上长树枝,树...
  • 二叉树是一种重要数据结构,与数组、向量、链表都是一种顺序容器,它们提供了按位置访问数据手段。但是有一个缺点,它们都是按照位置来确定数据,想要通过值来获取数据,只能通过遍历方式。而二叉树在很大程度...
  • 二叉树的镜像

    2016-05-08 00:19:00
    看到这个题目,你第一感觉就是完了,不懂啊,没关系,我们看看什么叫二叉树的镜像...看见图中的镜子了没,想想镜子起的作用,镜像就是这么来的 两颗二叉树特点分析: 1.都是二叉树(哈哈) 2.二叉树中数据完全相同。...
  • 5.1.3二叉树的定义

    2021-02-10 15:03:31
    5.1.3二叉树的定义1.为何要重点研究==每结点最多只有两个“叉”== 的树?...二叉树在树结构的应用中起着非常重要的作用。 因为对二叉的许多操作算法简单,而任何树都可以与二叉树相互转换,这样就解决了树的存储结
  • 二叉树的总结

    千次阅读 2014-02-19 17:05:00
    一,二叉树的定义   二叉树(Binary tree)是n(n≥0)个结点的有限集合。若n=0时称为空树,否则:  ⑴有且只有一个特殊的称为树的根(Root)结点;  ⑵若n>1时,其余的结点被分... 二叉树在树结构中起着非常重要的作用
  • 链式二叉树的实现.sln

    2020-06-17 09:18:04
    本例程详细讲解了链式二叉树的实现方法和实现的函数,对于学习数据结构中的链式二叉树具有很好的学习作用,可以充分理解二叉树的结构和特性
  • 最近已经很久没写博客主要是因为没时间,不过最近的这个二叉树我着实又很多的感悟,所以尽管要花时间,我还是想要写下来,希望对大家也有帮助,我会先从二叉树的一些性质讲起,并讲明该性质的作用,最后附上一道综合...
  • 现在有一个问题,已知二叉树的前序遍历和中序遍历: PreOrder: GDAFEMHZ InOrder: ADEFGHMZ 我们如何还原这颗二叉树,并求出他的后序遍历?   我们基于一个事实:中序遍历一定是 { 左子树中的节点集合 },root,{...
  • 了解非递归遍历过程中“栈”的作用和状态,而且能灵活运用遍历算法实现二叉树的其它操作。 2.实验内容 (1)二叉树的二叉链表的创建 (2)二叉树的前、中、后序遍历的递归算法和非递归算法的实现 (3)求二叉树...
  • 查找——平衡二叉树的实现(代码超详细注释)

    千次阅读 多人点赞 2018-09-03 11:05:37
    既然你搜索到了这篇文章,那么平衡二叉树的作用想必心中已经清楚了,我们接下来就直接来谈谈代码... 目录   知识准备  进阶讲解  代码实现 谢谢阅读 知识准备   啥?你又不知道,真拿你没办法,给你一...
  • 二叉树的建立(C语言)

    2021-06-08 21:08:16
    指针在二叉树的创建中主要起到数据正常传出自定义函数的作用。 为什么指针具备该作用呢。话不多说直接上代码: #include<stdio.h> void swap(int,int);//交换函数 int main() { int a = 1, b = 2; ...
  • 平衡二叉树(笔记)

    2018-12-13 20:08:00
    先介绍排序二叉树。...意义:排序二叉树的作用是在插入或者构建这棵树时,就是在对一个无序数列的一个排序过程!并且采用了二分思想,但是一般时间复杂度为log(n),最坏的情况依旧是O(n) 例如,最坏的情况如下...
  • 二叉树作为一种很特殊的数据结构,功能上有很大的作用!今天就来看看怎么计算一个二叉树的最大的宽度吧。 采用递归方式 下面是代码内容: int GetMaxWidth(BinaryTree pointer){ int width[10];//加入这棵树的最大...
  • 现在有一个问题,已知二叉树的前序遍历和中序遍历: PreOrder: GDAFEMHZ InOrder: ADEFGHMZ 我们如何还原这颗二叉树,并求出他的后序遍历? 我们基于一个事实:中序遍历一定是 { 左子树中的节点集合 },root,{ ...
  • 但每一次创建了二叉树,总想直观看一下二叉树的结序,以方便程序的调试。但二叉树的结构怎样才能直观显示出来呢?看了网上的一些资料和做法,要么看不懂,要么不满意。于是试着自己写代码,看能否达到目的。功夫不负...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,059
精华内容 423
关键字:

二叉树的作用