title: 树
date: 2018-06-02 00:05:36
tags: 数据结构

树形结构

一、树形结构

基本术语:
  • 结点: 数据元素 + 若干指向子树的分支

  • 结点的度:分支的个数

  • 树的度:树中所有结点的度的最大值

  • 结点的层次:假设根结点的层次为1,第k层的结点的子树根结点(也就是它的下一层)的层次为k+1

  • 树的深度:树中叶结点所在的最大层次

  • 有序树和无序树的区别:子树之间是否存在次序关系,即左右子树交换后还是不是同一棵树

  • **森林:**是m(m≥0)棵互不相交的树的集合

  • 树形结构的其他表示方法:

  • 树形结构和线性结构的区别:除第一个结点和最后一个结点外的中间结点有一个前驱多个后继,而线性结构是一个前驱一个后继

  • 树的存储结构:

    (1)双亲表示法: data|parent

    #define MAXSIZE 100 
    typedef char datatype; /*结点值的类型*/ 
    typedef struct node /*结点的类型*/ 
    { 	datatype data; 
    	int parent; /*结点双亲的下标*/ 
    } node; 
    typedef struct tree { 
    	node treelist[MAXSIZE];/*存放结点的数组*/ 
    	int length, root ; /* 树中实际所含结点的 个数及根结点的位置*/ 
    } tree;
    

    (2)孩子表示法:有指针、数组、链表三种方式表示法

    1、指针式

    #define m 3 /*树的度数*/ 
    typedef char datatype; /*结点值的类型*/ 
    typedef struct node { /*结点的类型*/ 
    	datatype data; 
    	struct node *child[m];/*指向子女的指针数组*/ 
    } node,* tree; 
    tree root;
    

    2、数组式

    #define m 3 
    #define MAXSIZE 20 
    typedef char datatype; 
    typedef struct node { 
       datatype data; 
       int child[m]; 
    } treenode; 
    treenode tree[MAXSIZE]; 
    int root ; 
    int length;
    

    3、链表式

    # define MAXSIZE 50 
    typedef char datatype; 
    typedef struct chnode { /*孩子结点的类型*/ 
    	int child; 
    	struct chnode *next; 
    } chnode, * chpoint;
    typedef struct { /* 树中每个结点的类型*/ 
    	datatype data; 
    	chpoint firstchild;/*指向第一个子女的指针*/ 
    	} node; 
    typedef struct { /*树的类型*/ 
    	node treelist [MAXSIZE]; 
    	int length, root; 
    } tree;
    

    (3)孩子兄弟表示法

    typedef char datatype;/*树中结点值的类型*/ 
    typedef struct node {/*树中每个结点的类型*/ 
    	datatype data; 
    	struct node * firstchild, *rightsibling; 
    } node, * pnode; 
    pnode root; /*指向树根结点的指针*/
    
  • 树的遍历:(指针式孩子表示法)

    (1)前序遍历 root–left–right

    (2)后序遍历 left–right–root

    (3)层次遍历

    #include <iostream>
    #include <algorithm>
    #include <cmath> 
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <map>
    #include <queue>
    #include <stack>
    #define ll long long 
    #define m 3
    const int maxn=100010;
    const int inf=0x3f3f3f3f;
    const double eps=1e-8;
    using namespace std;
    ll mod=1000000007;
    using namespace std;
    typedef struct node{
    	char data;
    	struct node* child[m]; 
    }node,*tree;
    tree root;//tree是node*的 
    void create(tree *p)//前序遍历建树 
    {
    	char ch;
    	if((ch=getchar())=='#')
    	*p=NULL;
    	else
    	{
    		*p=(tree)malloc(sizeof(node));
    		(*p)->data=ch;
    		for(int i=0;i<m;++i)
    		{
    			create(&(*p)->child[i]); 
    		}
    	}
    }
    void preorder(tree &p)
    {
    	if(p)
    	{
    		printf("%c",p->data);
    		for(int i=0;i<m;++i)
    			preorder(p->child[i]);
    	}
    }
    void postorder(tree p)
    {
    	if(p)
    	{
    		for(int i=0;i<m;++i)
    			postorder(p->child[i]);
    		printf("%c",p->data);
    	}
    }
    void levelorder(tree t)
    {
    	queue<tree>q;
    	q.push(t);
    	tree p;
    	while(!q.empty())
    	{
    		p=q.front();
    		printf("%c",p->data);
    		
    		for(int i=0;i<m;i++)
    			if(p->child[i])
    			q.push(p->child[i]);
    		
    		q.pop();
    	}
    }
    int main()
    {
        ios::sync_with_stdio(false);
        create(&root);
        preorder(root);//ABCEFHIGD
        //postorder(root);//BEHIFGCDA
        //levelorder(root);//ABCDEFGHI
        return 0;
    }
    
    

二、二叉树

  • 特征:

    (1)二叉树中每个非空结点最多只有两个子女.

    (2)二叉树中结点的子树要区分左子树和右子树, 即使在结点只有一棵子树的情况下也要明确指 出是左子树还是右子树。

  • 性质:

    (1)一棵非空二叉树的第i层上至多有2^i-1个结点 (i≥1)

    (2)深度为h的二叉树至多有2^h-1个结点(h>1)

    (3)对于任何一棵二叉树T,如果其终端结点数(即 叶结点数)为n0,度为2的结点数为n2,则n0=n2+1。

    证明:

    假设二叉树中总的结点个数为n ,度为1的结点个数为n1,则有: n=n0+n1+n2

    又由于在二叉树中除根结点外,其它结点均通过一条树枝且仅通过一条树枝与其父母结点相连,即除根结点外,其它结点与树中的树枝存在一一对应的关系;

    而二叉树中树枝的总条数为n1+2n2,因而二叉树总结点的个数为: n=n1+2n2+1 于是有: n0+n1+n2=n1+2*n2+1

    显然n0=n2+1成立。

    (4)对于具有n个结点的完全二叉树,如果按照从上到下、同一层次上的结点按从左到右的顺序对二叉树中的所有结点从1开始顺序编号,则对于序号为i的结点,有:

  • **满二叉树:**二叉树中所有终端结点均位于同一层次, 而其它非终端结点的度数均为2。(范围更小)

  • 完全二叉树:二叉树扣除其最大层次那层后即成为一棵满二叉树,且层次最大那层的所有结点均向左靠齐。即完全二叉树中只有最下面的两层结点的度数可以小于2,且最下面一层的结点都集中在该层最左边的若干位置上。(如图二) (范围更大)

  • **注意:**满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树。

    一般二叉树的存储结构


一般二叉树顺序存储:

#define MAXSIZE 20 
typedef char datatype; /*结点值的类型*/ 
typedef struct { 
    datatype data; 
    int lchild,rchild; 
} node; /*二叉树结点的类型*/ 
node tree[MAXSIZE]; 
int n; /*树中实际所含结点的个数*/ 
int root; /*存放根结点的下标*/

带双亲指示的二叉树顺序存储:

#define MAXSIZE 20 
typedef char datatype; /*结点值的类型*/ 
typedef struct 
{ 
    datatype data; 
    int lchild,rchild; 
    int parent; /*存放双亲结点的下标*/ 
} node; /*二叉树结点的类型*/ 
node tree[MAXSIZE]; 
int n; /*树中实际所含结点的个数*/ 
int root; /*存放根结点的下标*/


链式存储方式下二叉树结点数据结构:

typedef char datatype; /*结点属性值的类型*/ 
typedef struct node{ /*二叉树结点的类型*/ 
    datatype data; 
    struct node *lchild, *rchild; 
} bintnode; 
typedef bintnode* bintree; 
bintree root;

链式存储方式下带双亲指针的二叉树结点数据结构:

typedef char datatype; /*结点属性值的类型*/ 
typedef struct node{ /*二叉树结点的类型*/ 
    datatype data; 
    struct node *lchild, *rchild; 
    struct node *parent; /*指向双亲的指针*/ 
} bintnode; 
typedef bintnode *bintree; bintree root; /*指向二叉树根结点的指针*/

二叉树的遍历

  • 遍历方式

#include <iostream>
#include <algorithm>
#include <cmath> 
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <queue>
#include <stack>
#define ll long long 
#define m 3
const int maxn=100010;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
using namespace std;
ll mod=1000000007;
using namespace std;
typedef struct node{
	char data;
	struct node *lchild,*rchild; 
}bintnode;
typedef bintnode* bintree;
bintree root;//tree是node*的 
void create(bintree *t)
{
	char ch;
	if((ch=getchar())==' ')
	*t=NULL;
	else
	{
		*t=(bintnode*)malloc(sizeof(bintnode));//生成二叉树的根节点
		(*t)->data=ch;
		create(&(*t)->lchild);//递归实现左子树
		create(&(*t)->rchild);//递归实现右子树 	
	}
}
/*递归版遍历*/ 
void preorder(bintree t)
{
	if(t)
	{
		printf("%c",t->data);
		preorder(t->lchild);
		preorder(t->rchild);
	}
}
void midorder(bintree t)
{
	if(t)
	{
		midorder(t->lchild);
		printf("%c",t->data);
		midorder(t->rchild);
	} 
}
void postorder(bintree t)
{
	if(t)
	{
		postorder(t->lchild);
		postorder(t->rchild);
		printf("%c",t->data);
	}	
}
/*非递归版*/
 
int main()
{
    ios::sync_with_stdio(false);
    create(&root);
    preorder(root);
    midorder(root);
    postorder(root);
    return 0;
}

三、二叉搜索树(又称二叉排序树)

性质:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。

//这里还应该写一个二叉搜索树的实现及其算法

四、树堆(Treap)

Treap是一棵二叉排序树,它的左子树和右子树分别是一个Treap,和一般的二叉排序树不同的是,Treap纪录一个额外的数据,就是优先级。Treap在以关键码构成二叉排序树的同时,还满足堆的性质(在这里我们假设节点的优先级大于该节点的孩子的优先级)。

但是这里要注意的是Treap和二叉堆有一点不同,就是二叉堆必须是完全二叉树,而Treap可以并不一定是。

//各种树什么的开始蒙圈了 溜

留几个看着不错的博客吧,下次继续

平衡树

无旋treap

Treap图文详解

敲黑板!!

多动态图详细讲解二叉搜索树

平衡树总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值