手撕数据结构与算法——树(三指针描述一棵树)

简介: 手撕数据结构与算法——树(📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段,因为最近参加新星计划算法赛道(白佬),所以加快了脚步,果然急迫感会增加动力>——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的📖作者主页:king&南星📖专栏链接:数据结构🎉欢迎各位→点赞👏 + 收藏💞 + 留言🔔​💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾————————————————版权声明:本文为CSDN博主「热爱编程的小K」的原创文章,遵循CC 4.0 BY-S三指针描述一棵树)

9b9b67a20c5d4fddb2f4a78eda506af8.png

🏅文章目录

🌱树

一、🌲概念与定义

二、🌳定义与预备

三、🌴创建结点函数

四、🍀查找

五、🍁插入

六、🍃遍历

🌱树

一、🌲概念与定义

描述树结构:

和现实世界的树 反着画

根节点 枝干 叶子节点

同一层 兄弟 上层:父 叔叔 上层的上层:爷爷

下层:孩子 侄儿

树的高度:几代人

树退化成线性结构 : 一叉树(链表) N代单传

数据结构中的树是和现实倒着的

948f755b2fd24fd3994fa49db8a961aa.png

cf184e26f22745bc9bf90ab48ce529f4.png

详细解读:三个指针描述,一个指针指向父亲,一个指针指向兄弟,一个指针指向孩子,同时规则设定只有父亲的第一个孩子才可以有孩子

二、🌳定义与预备

先准备好头文件、结构体和函数声明

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>

#include<stdlib.h>

#include<stdbool.h>

#include<assert.h>

typedef struct treeNode

{

int data;                  //数据

struct treeNode* pParent;  //指向父

struct treeNode* pBrother; //指向第一个兄弟

struct treeNode* pChild;   //指向第一个孩子

}treeNode;

#define SIZE sizeof(treeNode)

//创建节点函数

treeNode* createNode(int data);

//在树中找一个节点,找到返回这个节点的地址,找不到返回NULL

treeNode* findNode( treeNode* root, int findData);

//插入一个节点到树中

//把insertData插入到*pRoot树中 如果isChild为真成为findData节点的孩子,否则成为findData节点的兄弟

bool intsertNode( treeNode** pRoot, int findData, int insertData, bool isChild);

//遍历

void print_Tree(treeNode* root);

三、🌴创建结点函数

这里利用一个技巧,直接使用内存设置函数memset函数,把三个指针内存都设置为0

treeNode* createNode( int data )

{

treeNode* newNode = (treeNode*)malloc(SIZE);

assert(newNode);

memset(newNode, 0, SIZE);  //内存都设置为0

newNode->data = data;

return newNode;

}

四、🍀查找

在树中找一个节点,找到返回这个节点的地址,找不到返回NULL

先在while循环中遍历同一层的兄弟,直到他下一个兄弟为空,切换到下一层,如此循环下去,如果找到则返回地址,如果没找到则返回空

treeNode* findNode(treeNode* root, int findData)  

{

if (NULL == root) return NULL;  //防呆

treeNode* pTemp;

treeNode* pnextChild = root;

while (true)

{

 pTemp = pnextChild;

 if (NULL == pnextChild) break;

 while( true )

 {

  //遍历兄弟层

  if (NULL == pTemp) break;

  if (findData == pTemp->data) return pTemp;

  pTemp = pTemp->pBrother;

 }

 //切换到下一层(孩子)

 pnextChild = pnextChild->pChild;

}

return NULL;

}

五、🍁插入

描述:插入一个节点到树中,把insertData插入到*pRoot树中 如果isChild为真成为findData节点的孩子,否则成为findData节点的兄弟

99513581e3b440b6a188d5fe8dc0f923.png

bool intsertNode(treeNode** pRoot, int findData, int insertData, bool isChild)

{

if (NULL == pRoot) return false; //防呆

if (NULL == *pRoot) //空树

{

 *pRoot = createNode(insertData);

 return true;

}

treeNode* pFind = findNode(*pRoot, findData);  //查找

if (NULL == pFind) return false;

treeNode* pNew, * pTemp;

//找到了

if (isChild) //新节点成为pFind指向节点的孩子

{

 //有孩子,新节点成为pFind节点孩子的最小兄弟

 if (pFind->pChild)

 {

  pTemp = pFind->pChild;

  pNew = createNode(insertData);

  while (pTemp->pBrother) pTemp = pTemp->pBrother;

  pTemp->pBrother = pNew;

  pNew->pParent = pFind;

  return true;

 }

 //pFind指向的节点没有孩子

 else

 {

  //有父,pFind不是根节点

  if (pFind->pParent)

  {

   //pFind是pFind->pPartent的第一个孩子

   if (pFind->pParent->pChild == pFind)

   {

    pNew = createNode(insertData);

    pFind->pChild = pNew;

    pNew->pParent = pFind;

    return true;

   }

   else

   {

    //pFind不是pFind->pParent的第一个孩子

    //新节点只能成为 pFind->pParent->pChild的孩子

    intsertNode(&(pFind->pParent), pFind->pParent->pChild->data, insertData, true);

   }

  }

  //无父,pFind是根节点

  else

  {

   pNew = createNode(insertData);

   pFind->pChild = pNew;

   pNew->pParent = pFind;

   return true;

  }

 }

}

else //新节点成为pFind指向节点的兄弟

{

 pTemp = pFind;

 while (pTemp->pBrother) pTemp = pTemp->pBrother;

 pNew = createNode(insertData);

 pTemp->pBrother = pNew;

 pNew->pParent = pFind->pParent;

 return true;

}

return false;

}

六、🍃遍历

和查找函数异曲同工

void print_Tree(treeNode* root)  

{

if (NULL == root) return NULL;  //防呆

treeNode* pTemp;

treeNode* pnextChild = root;

int cnt = 1;

while (true)

{

 pTemp = pnextChild;

 if (NULL == pnextChild) break;

 printf("第[%d]层:", cnt++);

 while (true)

 {

  //遍历兄弟层

  if (NULL == pTemp) break;

  printf("%d ", pTemp->data);

  pTemp = pTemp->pBrother;

 }

 printf("\n");

 //切换到下一层(孩子)

 pnextChild = pnextChild->pChild;

}

}

版权声明:本文为CSDN博主「热爱程的小K」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_72157449/article/details/129628960

相关文章
|
1月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
56 1
|
1天前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
9 2
|
1天前
|
JSON 前端开发 JavaScript
一文了解树在前端中的应用,掌握数据结构中树的生命线
该文章详细介绍了树这一数据结构在前端开发中的应用,包括树的基本概念、遍历方法(如深度优先遍历、广度优先遍历)以及二叉树的先序、中序、后序遍历,并通过实例代码展示了如何在JavaScript中实现这些遍历算法。此外,文章还探讨了树结构在处理JSON数据时的应用场景。
一文了解树在前端中的应用,掌握数据结构中树的生命线
|
17天前
|
C语言
数据结构基础详解(C语言):图的基本概念_无向图_有向图_子图_生成树_生成森林_完全图
本文介绍了图的基本概念,包括图的定义、无向图与有向图、简单图与多重图等,并解释了顶点度、路径、连通性等相关术语。此外还讨论了子图、生成树、带权图及几种特殊形态的图,如完全图和树等。通过这些概念,读者可以更好地理解图论的基础知识。
|
19天前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
19天前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
19天前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
1月前
|
存储 算法 Linux
【数据结构】树、二叉树与堆(长期维护)(1)
【数据结构】树、二叉树与堆(长期维护)(1)
|
1月前
|
算法
【数据结构】树、二叉树与堆(长期维护)(2)
【数据结构】树、二叉树与堆(长期维护)(2)
【数据结构】树、二叉树与堆(长期维护)(2)
|
26天前
crash —— 如何知道哪些数据结构内嵌了指定的数据结构或者内嵌了指向指定数据结构的指针
crash —— 如何知道哪些数据结构内嵌了指定的数据结构或者内嵌了指向指定数据结构的指针