线性表结束了,接下来是树, 其实线性结构就是树的一种特殊情况,
而我们的正常学习顺序也是从特殊到一般,所以也是理所应当的开始了解树的概念。
树:
基本概念:
- 结点的度:子树个数
- 树的度:树的所有结点中最大的度数
- 叶结点:度为0的结点(没有子树)
- 父结点:子节点的上一级结点
- 子结点:父节点的子节点
- 兄弟结点:拥有同一个父节点
- 路径和路径长度:两个节点之间边的数量
- 子孙结点:一个结点往下所有结点都是子孙结点
- 祖先结点:拥有子孙结点的就是所有子孙结点的祖先结点
- 结点的层次:根节点在1层,其他任一结点的层数是其父节点+1
- 树的深度:该树中所有节点中,最大的层次就是这棵树的深度
我看对于树,这个考核大纲中,树的下面,只有二叉树...:
- 树的定义和术语。
- 二叉树(完全二叉树、满二叉树)的定义和性质、二叉树的存储结构(顺序表示法和二叉链表表示法)。
- 二叉树遍历的递归算法。
- 树和森林转换为二叉树的方法。
所以我也只去实现这里面的内容了。
二叉树
什么是二叉树,二叉树的定义是?二叉树就是每个结点度最大为2的树,并且对于子结点有左右之分,(通俗的说:每个结点最多开俩叉的树) PS:其实还有空树。
二叉树的性质?
- 二叉树第i层最大结点数为 2 ^ ( i - 1 ) ,
- 总结点数为 2 ^ i - 1 (i ≥ 1) PS:其实就是二进制...
- n0 , n1, n2,分别代表一棵树中按度的数量分类的集合,如n0就是度为0的结点数量。有n0+n1+n2=所有结点,n0+n1+n2-1=边的数量 n0=n2+1(抽象理解,,假设:每有一个n0变成了n2,便会增加一个n0,而变成n1不影响n0数量,那么为什么n0比n2多一个呢,请参考一颗仅有一个n0的树,然后再把n0变成n2,会多出两个n0,因为第一个n2必须建立在有一个n0的基础上,它不能凭空产生,所以n0一定会比n2多一个)
二叉树的存放方式?数组(顺序存储结构),链表
二叉树的主要操作集?是否为空IsEmpty,遍历Traversal(*重要),创建Create
PS:遍历Traversal类型:先序,中序,后序,层次
数组实现:
#include <iostream>
using namespace std;
struct Tree
{
int* arr;
int lastIndex;
void Init()
{
arr=(int*)malloc(sizeof(int)*64);//为了方便写成固定
lastIndex = 0;
for (int i = 0; i < 64; i++)
{
arr[i] = 0x7fffffff;
}
}
void Add(int num)
{
arr[++lastIndex] = num;
}
void Remove(int i)
{
if(i<=lastIndex)
arr[i] = 0x7fffffff;
}
int GetLChild(int i)
{
return i * 2;
}
int GetRChild(int i)
{
return i * 2 + 1;
}
void PreTraversal(int root)
{
if ( arr[root]==0x7fffffff)return;
cout <<" ["<< arr[root]<<"] ";
PreTraversal(GetLChild(root));
PreTraversal(GetRChild(root));
}
void MidTraversal(int root)
{
if (arr[root] == 0x7fffffff)return;
MidTraversal(GetLChild(root));
cout << " [" << arr[root] << "] ";
MidTraversal(GetRChild(root));
}
void LastTraversal(int root)
{
if (arr[root] == 0x7fffffff)return;
LastTraversal(GetLChild(root));
LastTraversal(GetRChild(root));
cout << " [" << arr[root] << "] ";
}
void LayelTraversal(int root)
{
for (int i = 1; i < lastIndex+1; i++)
{
cout << " [" << arr[i] << "] ";
}
}
};
int main()
{
Tree a;
a.Init();
for (int i = 1; i < 10; i++)
{
a.Add(i);
}
cout << "前序";
a.PreTraversal(1);
cout <<endl;
cout << "中序";
a.MidTraversal(1);
cout << endl;
cout << "后序";
a.LastTraversal(1);
cout << endl;
cout << "层序";
a.LayelTraversal(1);
return 0;
}
链表实现:
#include <iostream>
using namespace std;
/////////////////////////////////////////////////////////////////////////////队列
struct Queue
{
int arr[1024];
int maxlen;
int left;//队列尾
int right;//队列头
int len;
void Init()
{
maxlen = 5;
left = 0;
right = -1;
len = 0;
}
bool IsNull()
{
if (len==0)return true;
return false;
}
bool IsFull()
{
if (len == maxlen)return true;
return false;
}
bool Enqueque(int num)
{
bool rt=false;
if (!IsFull())//一定不能满
{
right++;
arr[right%maxlen] = num;
len++;
rt = true;
}
return rt;
}
int Dequeque()
{
int rt = 0x7fffffff;
if (!IsNull())//一定不能是空的
{
rt = arr[left % maxlen];
len--;
left++;
}
return rt;
}
void Show()
{
for (int i=0; i < len ; i++)
{
cout<< arr[(left+i)%maxlen]<< " ";
}
cout << endl;
}
};
////////////////////////////////////////////////////////////////////////////
struct Node {
Node* L;
Node* R;
int value;
};
struct Tree {
Node* root;
int high;
int lastIndex;//用来插入的时候定位
void Init()
{
root = NULL;
high = 0;
lastIndex = 0;
}
void Add(int num)
{
if (root == NULL)//如此简单就将一个根节点插入了进来
{
root = (Node*)malloc(sizeof(Node));
root->value = num;
root->L = NULL;
root->R = NULL;
lastIndex = 1;
}
else
{//分两步,1计算结点插入的位置,2插入结点
//利用高度,得出批段,
//将lastindex- (2^high-1)可以算出该层的位置,
//然后根据2 , 4,8 来确定具体是谁的子树,?怎么实现呢?
//第一步生成一个数组,.....
bool* sx;
sx = (bool*)malloc(sizeof(bool)*high+1);
int tmp = pow(2, high);//最下一层,一共有多少个
int pos = lastIndex - (tmp - 1)+1; //最下一层从左往右数,的序号
if (pos > tmp)
{//这种情况直接在左斜边插入一个
high++;
for (int i = 0; i < high; i++)sx[i] = false;
}
else
{
int i = 0;
while (tmp >= 1)
{
tmp /= 2;
if (pos <= tmp)
{
sx[i++] = false;
if(pos>tmp)
pos -= tmp;
}
else
{
sx[i++] = true;
if (pos > tmp)
pos -= tmp;
}
}
}
//以上这个if else是结合pos和tmp定位到需要添加的地方(直接计算,免去遍历树的过程,提高效率)
cout << "添加路径:"; for (int i = 0; i < high; i++)cout << sx[i] << " "; cout << endl;//输出路径看看
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->value = num;
newNode->L = NULL;
newNode->R = NULL;
lastIndex++;
Node* n = root;
//创建新结点
for (int i = 0; i < high; i++)
{
if (sx[i])
{//R
if (i == high - 1 && n->R == NULL)
{
n->R = newNode;
}
else
{
n = n->R;
}
}
else
{//L
if (i == high - 1 && n->L == NULL)
{
n->L = newNode;
}
else
{
n = n->L;
}
}
}
//知道位置了,就直接迭代插入
}
}
void PreTraversal(Node* _root)
{
if (_root == NULL)return;
cout << " ["<<_root->value << "] ";
if (_root->L != NULL)PreTraversal(_root->L);
if (_root->R != NULL)PreTraversal(_root->R);
}
void MidTraversal(Node* _root)
{
if (_root == NULL)return;
if (_root->L != NULL)MidTraversal(_root->L);
cout << " [" << _root->value << "] ";
if (_root->R != NULL)MidTraversal(_root->R);
}
void LastTraversal(Node* _root)
{
if (_root == NULL)return;
if (_root->L != NULL)LastTraversal(_root->L);
if (_root->R != NULL)LastTraversal(_root->R);
cout << " [" << _root->value << "] ";
}
void LayelTraversal()
{
Queue q;
q.Init();
q.Enqueque((int)root);
for (int i = 0; i < lastIndex; i++)
{
Node* tmp = (Node*)q.Dequeque();
cout << " ["<< tmp->value <<"] ";
if (tmp->L != NULL)q.Enqueque((int) tmp->L);
if (tmp->R != NULL)q.Enqueque((int) tmp->R);
}
}
};
int main()
{
Tree t;
t.Init();
for (int i = 1; i <= 9; i++)
{
t.Add(i);
}
cout << "前序";
t.PreTraversal(t.root); cout << endl;
cout << "中序";
t.MidTraversal(t.root); cout << endl;
cout << "后序";
t.LastTraversal(t.root); cout << endl;
cout << "层序";
t.LayelTraversal(); cout << endl;
return 0;
}
emmm,关于树和森林转换为二叉树的方法。 以后再来补充吧,感觉要把我写二叉结构变成多叉结构。然后再转换为二叉树?然后再把很多二叉树合并成一个二叉树?。。。。有缘再补充吧