数据结构之二叉树
来源:互联网 发布:adc0804连单片机 编辑:程序博客网 时间:2024/06/01 10:07
1、基本概念
二叉树,顾名思义,就是子节点最多只有两个的树。由于最多只有两个,可以区分左右,我们称子节点为左子女和右子女,次序不可颠倒。根据二叉树的结构,我们可以得到以下特性:
1. 第i层的节点个数最多为2^(i-1)(i>=1)个;
2. 深度为h的二叉树最多有2^h -1(h>=1)个节点,最少为h个;
3. 若叶节点的个数为n1,度数为2的节点个数为n2,则n1=n2+1;
2、特殊结构
当二叉树满足一些特殊的条件时,会形成特殊的结构,可以很好的作为其他数据结构的底层结构,目前有如下几种特殊情况:
1. 完全二叉树。若二叉树的高度为h,则除了第h层的其他层都达到该层节点的最大个数,同时第h层的节点是从左至右连续排列的。由于节点顺序是紧密排列的,可以使用序列容器进行存储,主要应用于二叉堆。以下是完全二叉树的特性,设定根节点的索引位置为1:
* 对于索引位置为i的节点,其到根节点的节点总数也为i;
* 对于索引位置为i的节点,其左子女的索引位置为2*i,右子女的索引位置为2*i+1;
* 对于索引位置为i(i>1)的节点,其父节点的索引位置为int(i/2);
* 对于索引位置为i的节点,若节点总数为n且i>int(n/2),则该节点为叶子节点;
* 对于索引位置为i的节点,若节点总数为n且int((n-1)/2)>i,则该节点必有两个子节点;
* 对于任意节点,若其右子树的深度为d,则左子树的深度为d或d+1;
* 若子节点总数为n,则叶子节点个数为l= math.ceil(n/2)。
2. 满二叉树。二叉树的每一层的节点个数都达到最大个数,因而满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树。
3. 平衡二叉树。对于树中的任意节点,其左右子树的高度相差不超过1。平衡二叉树要保证高度平衡,避免出现链表式的树。
3、查找节点
在树中查找节点,就是采用递归方法,从根节点开始,一次判读根节点、左子树、右子树,从而找的对应的节点,一下是实现代码:
bool BTree::contains(int key, BTreeNode* &node){ if (node == NULL) { return false; } if (key == node->data) { return true; } return contains(key,node->leftChild) || contains(key,node->rightChild);}
4、插入节点
二叉树在插入时是没有固定规则,可自行定义,下面我使用构造满二叉树的方式进行插入,这里通过queue找到节点的插入位置,代码如下:
void BTree::insert(int key, BTreeNode* &node){ if (node == NULL) { node = new BTreeNode(key); } else { //按照插入顺序放置 queue<BTreeNode*> q; q.push(node); while(!q.empty()) { BTreeNode* temp = q.front(); q.pop(); if (temp->leftChild == NULL) { temp->leftChild = new BTreeNode(key); return; } if (temp->rightChild == NULL) { temp->rightChild = new BTreeNode(key); return; } q.push(temp->leftChild); q.push(temp->rightChild); } }}
5、删除节点
二叉树删除节点也是没有规则的,但不管使用什么规则,都要考虑下面三种情况:
1. 删除节点没有子节点。这种情况最简单,将该节点的父节点指向该节点的指针置为空,然后删除该节点即可;
2. 删除节点有一个子节点。此时将该节点的父节点指向该节点的指针置为指向改节点的子节点,然后删除该节点;
3. 删除节点有两个子节点。这里采用的策略是先查找到该节点的右子树中的最后一个节点,然后将查找到的节点的键值与该节点的键值进行交换,最后使用递归方法删除查找到的节点。
下面是二叉树删除的实现代码:
void BTree::remove(int key, BTreeNode* &node){ if (node == NULL) { return; } if (key == node->data) { if (node->leftChild != NULL && node->rightChild != NULL) { //查找子树的最后一个节点 queue<BTreeNode*> q; q.push(node->leftChild); q.push(node->rightChild); while(true) { BTreeNode* curNode = q.front(); q.pop(); if (curNode->leftChild != NULL) { q.push(curNode->leftChild); } if (curNode->rightChild != NULL) { q.push(curNode->rightChild); } if (q.empty()) { node->data = curNode->data; curNode->data = key; remove(key,node); return; } } } else { BTreeNode* temp = node; node = (node->leftChild != NULL)?node->leftChild:node->rightChild; delete temp; return; } } remove(key,node->leftChild); remove(key,node->rightChild);}
6、清理操作
若要清理整棵树的节点,可以使用递归的方法清理节点的左右子树,然后释放节点自己,下面是实现代码:
void BTree::clear(BTreeNode* &node){ if (node == NULL) { return; } clear(node->leftChild); clear(node->rightChild); delete node; node = NULL;}
7、综合结果
下面,我们对算法进行测试,结果如下:
BTree* tree = new BTree();for (int i = 0; i < 10; ++i){ tree->insert(i);}cout<<"contains 5:"<<tree->contains(5)<<endl; //contains 5:1cout<<"contains 10:"<<tree->contains(10)<<endl; //contains 10:0BTreeNode* minNode = tree->findMin();if (minNode != NULL){ cout<<"findMin:"<<minNode->data<<endl; //findMin:0}BTreeNode* maxNode = tree->findMax();if (minNode != NULL){ cout<<"findMax:"<<maxNode->data<<endl; //findMax:9}tree->breadthFirstTravel(); //bft:0 1 2 3 4 5 6 7 8 9tree->depthFirstTravel_DLR(); //depthFirstTravel_DLR:0 1 3 7 8 4 9 2 5 6tree->depthFirstTravel_LDR(); //depthFirstTravel_LDR:7 3 8 1 9 4 0 5 2 6tree->depthFirstTravel_LRD(); //depthFirstTravel_LRD:7 8 3 9 4 1 5 6 2 0tree->remove(1);tree->breadthFirstTravel(); //bft:0 9 2 3 4 5 6 7 8tree->depthFirstTravel_DLR(); //depthFirstTravel_DLR:0 9 3 7 8 4 2 5 6tree->depthFirstTravel_LDR(); //depthFirstTravel_LDR:7 3 8 9 4 0 5 2 6tree->depthFirstTravel_LRD(); //depthFirstTravel_LRD:7 8 3 4 9 5 6 2 0tree->clear();tree->breadthFirstTravel(); //bft:
8、效率分析
二叉树的查找操作需要遍历整棵树,其算法复杂度为O(n);插入操作根据插入策略的不同而不同的,平均查找到插入位置的算法复杂度为O(logn);删除操作由于要先查找到节点,其算法复杂度以查找操作一致。
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- 数据结构之二叉树
- BZOJ 2301 [HAOI2011]Problem b
- BZOJ2002 弹飞绵羊 (LCT)
- 二叉树的创建与先、中、后序遍历递归实现
- uwsgi xml 配置
- Tornado
- 数据结构之二叉树
- BZOJ 2820 YY的GCD
- MySQL的读写分离之Amoeba
- ubuntu 下 anaconda 安装插件
- Ubuntu安装oh-my-zsh
- 机器学习 1.回归
- 无等待地从一个消息队列中取得消息, OSQAccept()
- 读入一个自然数n,计算其各位数字之和,用汉语拼音写出和的每一位数字。
- UI设计原则 Material Design