文章目录

  • 目录
    • 二叉树
      • 1.二叉树的基本概念
      • 2.二叉树的应用和时间复杂度
      • 3.二叉树的插入
      • 4.二叉树的查找
      • 5. 二叉树的遍历
      • 6.二叉树的删除
    • 二叉树的基本操作
      • 1.二叉树的基础操作
      • 2.代码实现
    • 创建二叉树和三种遍历二叉树的方法

目录

  • 数据结构:

    • 逻辑结构:数组,栈,队列,字符串,树,图
    • 存储结构:顺序存储,链式存储
  • C++常用的数据结构有:string , stack , queue , deque , vector , list , map , iterators.

二叉树

1.二叉树的基本概念

树是一些节点的集合,节点之间用边链接,节点之间不能有环路。上层的节点称为父节点,下层节点称为子节点。最上层的节点称为根节点。

二叉树是特殊的树。对于每个节点而言,与之直接相连的子节点不能超过两个(可以为0)。左边的子节点称为左子树,右边的子节点称为右子树。如下图就是一颗二叉树:

与树相关的一些概念:
**叶子节点:**没有任何子节点的节点称为叶子节点
深度:对于任意节点N,其深度指的是从根节点到N的唯一路径的长。根的深度为0。深度最深的叶子节点的深度为树的深度。可以理解为:树根是一个入口,离树根越远,就越深。如上图:A、B、C的深度为1,D、E的深度为2。
: 对于任意节点N,从N到一片树叶的最远路径的长为N的高度。(只可以从从上到下不能经过从下到上的节点。)树叶的高为0。树的高为根的高。如上图,根的高度为2。A的高度为1,其他节点高度为0。

2.二叉树的应用和时间复杂度

二叉树是一种常见的数据结构,常常用于查找,也运用于unix等常见操作系统的文件系统中。c++STL(标准模板库)中的set和map也使用二叉树中的红黑树实现。

  • 二叉树的查找思想基于:在二叉树中,对于任意节点N,左子树中的所有项的值不大于节点N中存储的值,右子树中的所有项的值不小于节点N中存储的值。如下图:

    这样,在查找时,只需要不断比较需要查找的x与N的大小,若小于N中的值,只需要搜索左子树,若大于N中的值,只需要搜索右子树。这样每次就能缩小搜索的范围。经过证明,普通二叉树的平均时间复杂度是O(LogN)。

看到这里,我们发现其实二叉树的搜索思想和二分查找一致,每次不断的减少搜索范围。但是二者之间还是有区别的。

对于二分查找而言,每次的时间复杂度不会超过O(LogN)。但是对于二叉树,搜索时间的复杂度取决于树的形状。在最坏情况下可能达到O(N)。如下图,如果要找到10,则要查找5次。


那我们为什么还要使用二叉树而不直接使用二分查找来代替?

这是因为,二分查找一般基于数组,如果需要插入或删除数据,则会带来很大的开销。因为每次插入或者删除数据需要将改变节点之后的数据往后挪或者往前挪。但是对于二叉树而言,只需要改变一下指向下一个节点的指针就可以很方便的实现插入或者删除。而且一些特殊的二叉树如红黑树可以保证查找的最坏复杂度不超过O(LogN)。

所以,如果是对于静态数据,不需要改变的数据而言,采用数组存储,使用二分查找比较好。而对于动态数据,需要频繁插入或者删除数据的,采取二叉树存储是较好的。

3.二叉树的插入

思路:插入数据x,从根节点开始,不断比较节点与x的大小。若x小于节点,下一次比较x与节点的左子树,反之,比较x与节点的右子树。直到遇到一个空的节点,插入数据。(我们不考虑插入重复数据) 。如下图:

过程:比较4与7,4<7,再比较4与7的左子树6,4<6,比较4与6的左子树3,4>3,比较4与3的右子树,为空,插入4。

代码:

template< typename T>
void BinaryTree<T>::insert(const T &theElement, BinaryNode * &t ) {if ( nullptr == t ){  //如果插入的节点没有创建,则进行创建t = new BinaryNode (theElement);} else if ( theElement < t->element ) {  //如果插入的节点小于当前的节点,则继续搜索其左子树insert( theElement, t->leftNode );} else if ( theElement > t->element ) { //如果插入的节点大于当前的节点,则继续搜索其右子树insert ( theElement, t->rightNode );} else {//重复的数据不添加到树中  (找到节点后,直接插入到合适的位置)}
};

4.二叉树的查找

思路:与插入类似,不断比较插入值与节点的值。代码如下

template< typename T>
bool BinaryTree<T>::isFind(const T &theElement, BinaryNode * t ) const {if ( nullptr == t ){return false;} else if ( theElement < t->element ) {return isFind( theElement, t->leftNode );} else if ( theElement > t->element ) {return isFind ( theElement, t->rightNode );} else { //匹配return true;}
};

5. 二叉树的遍历

二叉树的遍历有三种方式:

  • 前序遍历(DLR):首先访问根结点。然后如果有子树,则对于左孩子也采用DLR的遍历规则。没有就忽略。然后如果有右子树,则对右子树也采用DRL的遍历规则。没有就忽略。
  • 中序遍历(LDR):首先访问根节点的左子树(对左子树也采用LDR),没有则忽略。再访问根节点。最后则对右子树也采用LDR的遍历规则,没有就忽略。
  • 后序遍历:首先访问根节点的左子树(对左子树也采用LRD),没有则忽略。再对右子树也采用LRD的遍历规则,没有就忽略。最后则对右子树也采用LRD的遍历规则,没有就忽略。

三种遍历方式其实是根据根节点的访问顺序命名的。根最先方位为前序,次之访问为中序遍历。最后访问为后序遍历。


使用递归实现
前序遍历:

template< typename T>
void BinaryTree<T>::preOrder( BinaryNode *bNode ) const {if( nullptr != bNode ) {std::cout << bNode->element << " " ;preOrder(bNode->leftNode);preOrder(bNode->rightNode);}};

中序遍历:

template< typename T>
void BinaryTree<T>::inOrder( BinaryNode *bNode ) const {if( nullptr != bNode ) {inOrder(bNode->leftNode);std::cout << bNode->element << " " ;inOrder(bNode->rightNode);}
};

后序遍历:

template< typename T>
void BinaryTree<T>::postOrder( BinaryNode *bNode ) const {postOrder(bNode->leftNode);postOrder(bNode->rightNode);std::cout << bNode->element << " " ;
};

6.二叉树的删除




代码

template< typename T>
void BinaryTree<T>::remove(const T &theElement, BinaryNode * &t ) {if( nullptr == t ) {return;} else {if ( theElement < t->element) {remove(t->leftNode);} else if ( theElement > t->element ) {remove (t->rightNode);} else if  (nullptr != t->leftNode && nullptr != t->rightNode ) {  //需要删除的节点两个儿子t->element = findMin(t->rightNode)->element;remove(t->element, t->rightNode);} else {BinaryNode * oldNode = t;t = ( nullptr!= t->leftNode) ? t->leftNode : t->rightNode;delete oldNode;}}
};
emplate< typename T>
typename BinaryTree<T>::BinaryNode * BinaryTree<T>::findMin(BinaryNode *bNode) const {if ( nullptr!= bNode) {while( nullptr != bNode->leftNode) {bNode = bNode->leftNode;}}return bNode;
}

二叉树的完整代码

二叉树的基本操作

1.二叉树的基础操作

  • 1.创建二叉树
  • 2.递归输出二叉树
    • 2.1递归先序输出
    • 2.2递归中序输出
    • 2.3递归后序输出
  • 3.非递归输出
    • 3.1非递归先序输出
    • 3.2非递归中序输出
    • 3.3非递归后序输出
  • 4.层次遍历二叉树
  • 5.求树高
  • 6.求树叶子节点
  • 7.按值查找对应节点,输出左孩子结点值和右孩子结点值
  • 8.计算所有节点数

2.代码实现

#include<iostream>
#include<string>
#include<stack>
#include<deque>
#include<fstream>
using namespace std;//const int MAX_N = 100;
//数据节点
class Node
{public:char data;//数据class Node *lchild;//左节点class Node *rchild;//右节点
};//二叉树
class Tree
{public:Tree(){}~Tree(){}//构建二叉树void Create(string name){ifstream readfile;string str;readfile.open(name);if (readfile.is_open()){getline(readfile, str);//读取一行}readfile.close();CreateNode(str);//构建二叉树}//先序遍历非递归算法void Disp(){if (t == NULL){return;}stack<Node *> m_stack;//定义栈m_stack.push(t);while (!m_stack.empty()){Node *p = m_stack.top();//赋值一份当前双亲节点cout << p->data << ends;m_stack.pop();if (p->rchild)//先存储右子树,确保先输出左子树{m_stack.push(p->rchild);}if (p->lchild)//后存储左子树{m_stack.push(p->lchild);}}}//非递归中序遍历二叉树void DispMid(){if (t == NULL){return;}Node *p = t;stack<Node *>m_stack;while (p != NULL || !m_stack.empty()){while (p != NULL)//一路直走至左下角{m_stack.push(p);p = p->lchild;}if (!m_stack.empty()){p = m_stack.top();//备份当前栈顶地址m_stack.pop();cout << p->data << ends;p = p->rchild;}}}//非递归后序遍历二叉树void DispBehid(){if (t == NULL){return;}Node *pre = NULL, *p = t;stack<Node *>m_stack;while (p != NULL || !m_stack.empty()){while (p != NULL)//一路直走至左下角{m_stack.push(p);p = p->lchild;}p = m_stack.top();//右子树为空或者已访问,输出当前节点if (p->rchild == NULL || p->rchild == pre){cout << p->data << ends;pre = p;//将当前结点地址赋值pre作为下一次判断标志,防止重复访问m_stack.pop();p = NULL;//p赋值空以便访问右子树}else{p = p->rchild;//访问子树的右子树}}}//层次遍历void level_display(){if (t == NULL){return;}deque<Node *>m_qu;//定义队列m_qu.push_back(t);//树根入队列while (!m_qu.empty()){Node *p = m_qu.front();//拷贝当前对头cout <<p->data << ends;//输出m_qu.pop_front();if (p->lchild)//左孩子入队列{m_qu.push_back(p->lchild);}if (p->rchild)//右孩子入队列{m_qu.push_back(p->rchild);}}}//递归先序遍历输出二叉树void display(){cout << "递归先序:";output(t);cout << endl;}//递归中序遍历输出二叉树void displayMid(){cout << "递归中序:";outputMid(t);cout << endl;}//递归后序遍历输出二叉树void displayBhind(){cout << "递归后序";outputBhind(t);cout << endl;}//二叉树高度void Height(){int height = get_height(t);cout << "Height: " << height << endl;}//输出叶子节点值void display_leaf(){cout << "Leaves: ";output_leaf(t);cout << endl;}//查找二叉树中值data域为elem的节点void find_node(char elem){Node *res = NULL;res = find_node(t, elem, res);if (res != NULL){cout << "nice." << endl;if (res->lchild){cout << "left child:";cout << leftchild(res)->data << endl;}if (res->rchild){cout << "right child:";cout << rightchild(res)->data << endl;}}else{cout << "NO." << endl;}}//计算节点数void nodes_count(){int sum;if (t == NULL)//若为空,则0个节点{sum = 0;}else{sum = node_count(t);cout << "Total Nodes:" << sum + 1 << endl;}}
private:Node *t;//构建二叉树void CreateNode(string str){stack<Node *> m_stack;Node *p;int k;while (str.length() != 0){//若当前为'(',将双亲节点推入栈,下一位存储的p值作为左节点处理if (str[0] == '('){m_stack.push(p); k = 1;}//为右括号则栈顶退出一位else if (str[0] == ')'){m_stack.pop();}//为',',则下一个字符作右节点处理else if (str[0] == ','){k = 2;}//存储值用作双亲结点else{p = (Node *)malloc(sizeof(Node));p->data = str[0];p->lchild = p->rchild = NULL;//树根为空时,将第一个节点作为树根并赋值给私有成员变量if (t == NULL){t = p;}//树根不为空else{if (k == 1)//作为左节点处理,将栈中双亲节点的左指针指向当前节点{m_stack.top()->lchild = p;}else//作为右节点处理{m_stack.top()->rchild = p;}}}//重构串,除去首字符,并将串长度减小1str.assign(str.substr(1, str.length() - 1));}}//递归先序遍历输出二叉树void output(Node *t){if (t != NULL)//当树根不为空时{cout << t->data;//输出if (t->lchild != NULL || t->rchild != NULL)//左/右结点不为空时递归到下一层{cout << "(";output(t->lchild);if (t->rchild != NULL)//当左节点遍历结束后,左节点递归返回一层,递归右节点{cout << ",";}output(t->rchild);cout << ")";}}}//递归中序遍历二叉树void outputMid(Node *t){if (t == NULL)//空则返回{return;}else{cout << "(";outputMid(t->lchild);//递归左孩子节点if (t->rchild != NULL){cout << ",";}cout << t->data;//输出outputMid(t->rchild);//递归右孩子结点cout << ")";}}//递归后序遍历输出二叉树void outputBhind(Node *t){if (!t)//空则返回{return;}else{cout << "(";outputBhind(t->lchild);//递归左孩子节点if (t->rchild != NULL){cout << ",";}outputBhind(t->rchild);//递归右孩子结点cout << t->data;//输出cout << ")";}}//求树高int get_height(Node *t){int leftheight, rightheight;if (t == NULL)//递归至不存在子节点时返回0{return 0;}else{leftheight = get_height(t->lchild);//递归求左子树高度rightheight = get_height(t->rchild);//递归其右子树高度return leftheight > rightheight ? leftheight+1 : rightheight+1;//递归返回时返回最大值}}//查找左节点Node *leftchild(Node *p){return p->lchild;}//查找右节点Node *rightchild(Node *p){return p->rchild;}//输出叶子节点void output_leaf(Node *t){if (t != NULL)//树根不为空时{//当前节点没有子节点时输出节点数据if (t->lchild == NULL&&t->rchild == NULL){cout << t->data << ends;}output_leaf(t->lchild);//递归左子树output_leaf(t->rchild);//递归右子树}}//查找二叉树中值data域为elem的节点Node * find_node(Node *t, char elem, Node *res = NULL){//Node *res = NULL;if (t == NULL)//若当前节点为空,则返回结束{return NULL;}else{if (t->data == elem)//若找到值,返回地址{//res = t;return t;}else{if (res == NULL)//若保存结果的指针不为空,则递归查找左节点{res = find_node(t->lchild, elem, res);}if (res == NULL)//若保存结果的指针不为空,且左节点为搜索到,则递归查找右节点{res = find_node(t->rchild, elem, res);}}return res;}}//计算节点数int node_count(Node *t){int lcount = 0, rcount = 0;if (t == NULL)//空则返回{return 0;}else{if (t->lchild != NULL)//遍历左孩子节点{lcount = node_count(t->lchild);lcount += 1;}if (t->rchild != NULL)//遍历右孩子节点{rcount = node_count(t->rchild);rcount += 1;}return lcount + rcount;//返回当前左右孩子节点数}}
};int main()
{Tree m_tree;m_tree.Create("data");m_tree.display();//递归先序输出m_tree.displayMid();//递归中序输出m_tree.displayBhind();//递归后序输出m_tree.Height();//树高m_tree.display_leaf();//叶子节点cout << "非递归先序:";//cout << "Fir:";m_tree.Disp();//非递归先序遍历cout << endl;cout << "非递归中序:";//cout << "Mid:";m_tree.DispMid();//非递归中序遍历cout << endl;cout << "非递归后序:";//cout << "Bac:";m_tree.DispBehid();//非递归后序遍历cout << endl;cout << "层次遍历:";m_tree.level_display();//层次遍历cout << endl;cout << "Input element:";char elem;cin >> elem;m_tree.find_node(elem);//按节点值查找m_tree.nodes_count();//计算节点数return 0;
}

创建二叉树和三种遍历二叉树的方法


#include<iostream>
#include<fstream>
#include<string.h>using namespace std;  //定义二叉树的结构体
typedef struct BTree{int val;struct BTree *left , *right;
}BTree; //二叉树类的实现
class Tree{public:Tree();~Tree();//其他操作方法BTree *create_node(int level,string pos);  void PreOrder(BTree *t);   //先序遍历   void InOrder(BTree *t);    //中序遍历   void PostOrder(BTree *t);  //后序遍历BTree* root; //定义根节点
};BTree* Tree::create_node(int level,string pos){int data;BTree *node = new BTree;cout<<"please enter data:level"<<level<<" "<<pos<<endl;cin>>data;//若输入的数据为0,则把该结点的子结点置为空   if(data == 0)  {  return NULL;  }  node->val= data;    /*create_node()的    参数用于在给二叉树赋值时表明 现在赋值的是哪个结点*/   node->left = create_node(level+1,"left");  node->right= create_node(level+1,"right");             return node;
}void Tree::PreOrder(BTree *t)
{  if(t)  {  cout<<t->val<<endl;;  PreOrder(t->left);  PreOrder(t->right);                }
}   void Tree::InOrder(BTree *t)
{  if(t)  {  InOrder(t->left);  cout<<t->val<<endl;;  InOrder(t->right);  }
}  void Tree::PostOrder(BTree *t)
{  if(t)  {  PostOrder(t->left);  PostOrder(t->right);  cout<<t->val<<endl;    }
}  int main()
{  Tree tree;  tree.root = tree.create_node(1,"root");  cout<<"Pre"<<endl;  tree.PreOrder(tree.root);  cout<<"In"<<endl;  tree.InOrder(tree.root);  cout<<"Post"<<endl;  tree.PreOrder(tree.root);     return 0;
}

输入:
7
4 10
3 5 8 12
输出:

数据结构和算法(06)---二叉树(c++)相关推荐

  1. 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树

    [本文谢绝转载,原文来自http://990487026.blog.51cto.com] 树 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树二叉树的创建,关系建立二叉树的创建 ...

  2. 常考数据结构与算法:输出二叉树的右视图

    题目描述 请根据二叉树的前序遍历,中序遍历恢复二叉树,并打印出二叉树的右视图 上图树的右视图为:{1,4,3,7} 做此题之前可以先做下面3道题: 1. 常考数据结构与算法:求二叉树的层序遍历 2.常 ...

  3. 数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡二叉树

    数据结构与算法之二叉树的序列化和反序列化及判断一棵树是否为平衡而二叉树 目录 二叉树的序列化和反序列化 判断一棵树是否为平衡而二叉树 1. 二叉树的序列化和反序列化 1. 递归版本序列化和反序列化 代 ...

  4. 数据结构与算法之二叉树的先序遍历,中序遍历,后序遍历

    数据结构与算法之二叉树的先序遍历,中序遍历,后移遍历 目录 实现二叉树的先序,中序,后序遍历,包括递归方式和非递归方式 在二叉树中找到一个节点的后继节点 1. 实现二叉树的先序,中序,后序遍历,包括递 ...

  5. 数据结构与算法之-----二叉树(一)

    [ 写在前面的话:本专栏的主要内容:数据结构与算法. 1.对于初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到专栏前面的内容,包括具体数据结构的应用,所使用到的数据结构,也是自己构建的,未使用 ...

  6. 数据结构与算法:二叉树专题

    数据结构与算法:二叉树专题 前言 前提条件 基础知识 二叉树链式存储结构 二叉树中序遍历 二叉树层序遍历 常见编程题 把一个有序整数数组放到二叉树中 逐层打印二叉树结点数据 求一棵二叉树的最大子树和 ...

  7. 数据结构与算法练习-二叉树中序遍历

    python数据结构与算法练习-二叉树中序遍历 二叉树中序遍历 思路 python实现 二叉树中序遍历 链接: link. 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 样例 输入:ro ...

  8. 常考数据结构与算法:求二叉树的层序遍历

    题目描述 给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, 该二叉树层序遍历的结果是 [ [3], [9,20], ...

  9. 数据结构与算法--重建二叉树

    二叉树 树在实际编程中经常遇到地一种数据结构.上一篇中我们解释了二叉树及其原理,从中可以知道,树地操作会涉及到很多指针地操作,我们一般遇到地树相关地问题差不多都是二叉树.二叉树最重要地莫过于遍历,即按 ...

  10. 【数据结构与算法】二叉树

    树 1.树.二叉树 2.二叉查找树 3.平衡二叉树.红黑树 4.递归树 一.树 1.树的常用概念 根节点.叶子节点.父节点.子节点.兄弟节点,还有节点的高度.深度以及层数,树的高度. 2.概念解释 节 ...

最新文章

  1. java phantomjd linux_linux安装phantomjs
  2. 为什么曾经厉害的人突然不厉害了?
  3. python xpath语法-XPath语法和lxml模块(数据提取)
  4. [译] APT分析报告:11.深入了解Zebrocy的Dropper文档(APT28)
  5. the title and note has maintained the same text type
  6. 史上首次!世界杯使用视频裁判
  7. 开源 免费 java CMS - FreeCMS1.9 会员组管理
  8. UNIX(多线程):27---多线程并发之原子操作与无锁编程
  9. 云重磅 | 没有硬件,苹果发布多款“云服务”;阿里云发布基于公共云的虚拟GPU服务;中国移动首发5G套餐...
  10. ORACLE DUAL表详解
  11. 【Leetcode】102. 二叉树的层次遍历
  12. 【kafka】flink kafka NullPointerException Timeout position partition could be determined
  13. Scala 学习(四) 集合之List
  14. php dom xml解析,PHP使用DOM解析XML
  15. 【中秋福利】Linux系统从入门到精通推荐的书籍——中秋限时送书活动
  16. in packet sniffer
  17. 计算机科普小知识大全,电脑小白知识科普 10个Win10实用技巧科普
  18. IP6K防尘试验测试
  19. 多源传感器GNSS INS 视觉 LiDAR 组合导航与SLAM开源项目总结
  20. 百万冲顶 获取复活币

热门文章

  1. 搞IT也不能不懂“五险一金”啊
  2. STM32移植UCGUI3.90笔记
  3. 奥拉星插件flash下载手机版下载安装_终于等到你!安卓微信7.0.13内测版发布 支持夜间模式 附下载地址!...
  4. python迭代器创建序列_Python 中迭代器与生成器实例详解
  5. Apsara Clouder专项技能认证:实现调用API接口
  6. ios开发问题汇总(一)
  7. matlab 填充斜线,请教一个关于柱状图的问题--填充采用斜线之类的,不能是颜色...
  8. 【牛客 - 82B】区间的连续段(贪心,建图,倍增)
  9. 【HDU - 6184】Counting Stars(三元环计数,二分,优化暴力,O(m*sqrt(m)),图论)
  10. 【CodeForces - 215C 】Crosses (思维,图形题)