数据结构(一)——二叉树的性质与两种遍历方法

二叉树的存储

1. 二叉树的性质
  • 性质1二叉树的每个结点最多有两个子结点,分别为左孩子、右孩子,以他们为根的子树称为左子树、右子树。
  • 性质2二叉树的第i层最多有2i-1个结点。
1.1满二叉树

定义:在二叉树中, 每一层的结点数都是满的 (见二叉树的性质2),一个n层的满二叉树,结点数量一共有2n-1个。
在这里插入图片描述

1.2完全二叉树

定义:满二叉树中 只有最后一层有缺失的结点,并且 缺失的编号都在最后
性质:以一颗结点数量为k的完全二叉树,设0号点为根节点。

  • 性质1:i >1的结点,其父结点是i/2
  • 性质2:如果结点i有孩子,那么它的左孩子是2i,右孩子是2i+1
2.二叉树的存储结构

二叉树一般用指针来实现,并指向左、右子结点。

struct TreeNode {
	char value;			//结点值
	TreeNode *l, *r;		//指向左、右两个子结点
};

完全二叉树可以用数组实现,会更加方便。

二叉树的遍历

1.深度优先遍历

blog.csdnimg.cn/20200507194553816.png)
根节点访问顺序分类:
在这里插入图片描述

tip:根结点已粗体

  • 先序遍历 (根节点——>左儿子——>右儿子):
    A-BDE-CFG
  • 中序遍历 (左儿子——>根节点——>右儿子):
    DBE-A-FCG
  • 后序遍 (左儿子——>右儿子——>根节点
    DEB-FGC-A

在进行具体遍历的情况下,应在最后一层结点后面加上空的左右结点NULL,NULL是一条路走完的标志,递归终止的条件。在这里插入图片描述

1.1先序遍历

1.1.1递归写法:

在使用递归方法时,

void PreOrder(const TreeNode *root) {
    if (root == NULL) {
        printf("# ");                 //若结点为空
        return;
    }
    printf("%c ", root->value);        //输出根节点的值
    PreOrder(root->l);             //前序访问左子树
    PreOrder(root->r);            //前序访问右子树
}

1.1.2非递归写法
前序遍历中,栈中元素是自己和自己的左孩子都访问过了,而右孩子还没有访问到的节点。
往左边走,一边输出一边压栈,直到遇NULL,开始弹出栈顶。

void PreOrder_(TreeNode *root) {
    stack<TreeNode *> s;
    TreeNode *cur, *top;
    cur = root;       //用cur指针指向当前访问的结点
    while (cur != NULL || !s.empty()) {//返回上一个根节点 
        while (cur != NULL) {//当前节点非空则输出数值value,压入栈中。
            printf("%c ", cur->value);
            s.push(cur);
            cur = cur->l;//继续指向当前结点的左孩子 
        }
        //直至左孩子为空,从栈中拿出栈顶结点top。
        top = s.top();
        s.pop();
        //上面已经确定了根节点,便可直接访问到右孩子。 
        cur = top->r;
    }
}
1.2中序遍历

1.2.1递归写法:

void InOrder(const TreeNode *root) {
    if (root == NULL) {             //判断节点是否为空
        printf("# ");
        return;
    }
    InOrder(root->l);           //中序遍历左子树
    printf("%c ", root->value);     //访问节点值
    InOrder(root->r);          //中序遍历右子树
}

1.2.2非递归写法:
而中序访问时栈中保存的元素是节点自身和它的右子树都没有被访问到的节点地址。
沿着最左边往下访问,路过的节点全部压栈,直到遇到空节点。


1.3后序遍历

1.3.1递归写法:

void PostOrder(TreeNode *root)  {
    if (root == NULL)  {
        printf("# ");
        return;
    }
    PostOrder(root->l);			//后序遍历左子树
    PostOrder(root->r);			//后序遍历右子树
    printf("%c ", root->value);		//访问节点值
}

1.3.2非递归写法:
栈中保存的元素是它的右子树和自身都没有被遍历到的节点。
与中序遍历不同的是先访问右子树,回来的时候再输出根节点的值。
多一个last指针指向上一次访问到的节点,用来确认是从根节点的左子树返回的还是从右子树返回的。

void PostOrder_(TreeNode *root) {
    stack<TreeNode *> s;
    TreeNode *cur, *top, *last = NULL;
    cur = root;
    while (cur != NULL || !s.empty()) {
        while (cur != NULL) {
            s.push(cur);
            cur = cur->l;
        }

        top = s.top();

        if (top->r == NULL || top->r == last) {
            s.pop();
            printf("%c ", top->value);
            last = top;
        }
        else {
            cur = top->r;
        }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
1. 什么是二叉树二叉树是一种形结构,其中每个节点最多有两个子节点。一个节点的左子节点比该节点小,右子节点比该节点大。二叉树通常用于搜索和排序。 2. 二叉树遍历方法有哪些? 二叉树遍历方法包括前序遍历、中序遍历和后序遍历。前序遍历是从根节点开始遍历,先访问根节点,再访问左子,最后访问右子。中序遍历是从根节点开始遍历,先访问左子,再访问根节点,最后访问右子。后序遍历是从根节点开始遍历,先访问左子,再访问右子,最后访问根节点。 3. 二叉树的查找方法有哪些? 二叉树的查找方法包括递归查找和非递归查找。递归查找是从根节点开始查找,如果当前节点的值等于要查找的值,则返回当前节点。如果要查找的值比当前节点小,则继续在左子中查找;如果要查找的值比当前节点大,则继续在右子中查找。非递归查找可以使用栈或队列实现,从根节点开始,每次将当前节点的左右子节点入栈/队列,直到找到要查找的值或者栈/队列为空。 4. 二叉树的插入与删除操作如何实现? 二叉树的插入操作是将要插入的节点与当前节点的值进行比较,如果小于当前节点的值,则继续在左子中插入;如果大于当前节点的值,则继续在右子中插入。当找到一个空节点时,就将要插入的节点作为该空节点的子节点。删除操作需要分为三种情况:删除叶子节点、删除只有一个子节点的节点和删除有两个子节点的节点。删除叶子节点很简单,只需要将其父节点的对应子节点置为空即可。删除只有一个子节点的节点,需要将其子节点替换为该节点的位置。删除有两个子节点的节点,则可以找到该节点的后继节点(即右子中最小的节点),将其替换为该节点,然后删除后继节点。 5. 什么是平衡二叉树? 平衡二叉树是一种特殊的二叉树,它保证左右子的高度差不超过1。这种平衡可以确保二叉树的查找、插入和删除操作的时间复杂度都是O(logn)。常见的平衡二叉树包括红黑和AVL

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你脸上有BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值