【考研】树的代码集和算法

本文详细介绍了森林、二叉树、二叉排序树的各种结构,包括双亲表示法、孩子表示法、孩子兄弟表示法,并提供了相应的代码实现。此外,还探讨了二叉树的顺序存储和链式存储操作,如前序、中序、后序遍历,以及层次遍历。文章进一步讲解了二叉排序树的构建、查找、删除等操作,并讨论了线索二叉树的构造。最后,讨论了二叉树的性质,如完全二叉树、高度计算、宽度计算等,以及二叉排序树的相关算法。
摘要由CSDN通过智能技术生成

主要是将森林,二叉树,二叉排序树一系列的结构和算法总结一下,代码均来自于王道书以免以后忘记哈哈


森林.结点结构


双亲表示法

#define MaxSize 100
typedef struct TNode{	//双亲结点数据类型 
	ElemType data;	//结点数据 
	int parent;		//双亲结点下标 
} TNode;

typedef struct {			//树的双亲结构 
	TNode node[MaxSize];	//结点数组
	int n					//结点数量 
}Tree; 

孩子表示法

#define MaxSize 100
typedef struct CNode{	//孩子结点数据类型 
	int child;		//该孩子在表头数组的下标
	struct CNode *next;	//指向该结点下一个孩子结点 
}CNode , *child; 

typedef struct {	//孩子结点数据类型 
	ElemType data;	//结点数据域 
	child firstchild;	//指向该结点的第一个孩子结点 
}TNode;	 

typedef struct {
	TNode nodes[MaxSize];	//结点数据域 
	int n;	//树中结点个数 
}tree;

孩子兄弟表示法

typedefc struct CSNode{		//孩子兄弟结点数据类型 
	ElemType data;		//该结点的数据域 
	struct CSNode *firstchild , *rightchild;	//指向该节点的第一个孩子和该节点的有兄弟结点 
}CSNode; 

二叉树


结点结构


顺序存储

#define MAXSize 100
typedef struct stree{
	ElemType bitTree[MaxSize];
	int pointer;	//结点数量
}STree;

链式存储

typedef struct BiTNode{	//二叉树结点结构 
	ElemType data;	//数据域
	struct BiTNode *lchild , *rchild;	//指向该节点的左、右孩子指针	
}BiNode  , *BiTree; 

顺序操作

初始化

void InitSTree(STree &T)
{
	for(int i = 0; i < MaxSize ; i++)
		T[i] = '\0';
	T.pointer = 0;
}

顺序二叉树的创建

void CreateSqBiTree(SqBiTree T)//层序输入数据
{
	char ch;
	fflush(stdin);//防止回车'\n'干扰输入
	for(int i = 1; i < MAX; i++)			
	{
		scanf("%c", &ch);
		if(ch != '#')//#代表空
			T[i] = ch;
		if(ch == '%')//%作为输入结束符号
			break;
	}
} 

增加根结点

void Insert_STree_root(STree &T , ElemType x){
	T.bitTree[1] = x;
	T.pointer++;
	return 1;
}

删除根节点

void Desert_STree_Root(STree &T ,ElemType x){
	x = bitTree[1];
	T.pointer--;
	return 1;
}

增加左结点

void Insert_STree_Left(STree &T ,int i , ElemType x){
	if( i >= MaxSize || i < 0 ){
		cout<<"argument is false!"<<end1;
		return -1;
	}
	T.bitTree[2*(i+1)] = x;
	T.pointer++;
	return 1;
}

增加右节点

void Insert_STree_Right( STree &T ,int i ,ElemType x ){
	if( i > MaxSize || i < 0){
		cout<<"argument is false!"<<end1;
		return -1;
	}
	T.bitTree[2*(i+1)+1] = x;
}

删除左节点

void Desert_STree_Left(STree &T , int i ,ElemType *x){
	if( i >= MaxSize || i<0){
		cout<<"argument is false">>end1;
		return -1
	}
	x = T.bitTree[2*(i+1)];
	T.pointer--;
	return 1;
}

删除右节点

void Desert_STree_Right(STree &T , int i ,ElemType x){
	if( i > MaxSize || i < 0 ){
		cout<<"argument is false"end1;
		return -1;
	}
	x = bitTree[2*(i+1)+1];
	T.pointer--;
	return 1;
}

链式操作


遍历


顺序形式

递归形式
//三种遍历方式:前序、中序、后序
//前序遍历
void STree_Traver_1(STree &T,int i)
{
	cout<<T.bitTree[i]<<" ";
    if(T.bitTree[2*i]!='0'
    	STree_Traver_1(T,2*i);		
    if(T.bitTree[2*i+1]!='0')
    	STree_Traver_1(T,2*i+1);
}

//中序遍历
void STree_Traver_2(STree &T,int i)
{
    if(T.bitTree[2*i]!='0')
	    STree_Traver_2(T,2*i);
    cout<<T.bitTree[i]<<" ";
    if(T.bitTree[2*i+1]!='0')
	    STree_Traver_2(T,2*i+1);
}

//后序遍历
void STree_Traver_3(STree &T,int i)
{
    if(T.bitTree[2*i]!='0')
	    STree_Traver_3(T,2*i);
    if(T.bitTree[2*i+1]!='0')
	    STree_Traver_3(T,2*i+1);
    cout<<T.bitTree[i]<<" ";
}

非递归形式
/前序遍历
int STree_Traver_1_no(STree &T)
{
    stack<int> s({'0'});
    int p=1,q;
    if(STree_empty(T))
    {
        cout<<"tree is empty!"<<endl;
        return -1;
    }
do{
    cout<<T.bitTree[p]<<" ";
    q=p*2+1;
    if(T.bitTree[q]!='0')
        s.push(q);
    p=p*2;
    if(T.bitTree[p]=='0') //到树的底部了,回退
    {
        p=s.top();
        s.pop();
    }
 }while(T.bitTree[p]!='0');
 
    return 1;
}

//中序遍历
int STree_Traver_2_no(STree &T)
{
    stack<int> s;
    int p=1;
    int b=1;
    /*
    if(STree_empty(T))
    {
        cout<<"tree is empty!"<<endl;
        return -1;
    }
    */
    do
    {
        while(T.bitTree[p]!='0')
        {
            s.push(p);
            p=p*2;
        }
        if(s.empty()) b=0;
        else {
        p=s.top();
        s.pop();
        cout<<T.bitTree[p]<<" ";
        p=p*2+1;
        }
    }while(b!=0);
    return 1;
}

//后序遍历
int STree_Traver_3_no(STree &T)
{
    int p=1;
    int b=1,top=0;
    int s1[20],s2[20];
    do{
        while(T.bitTree[p]!='0')
        {
            s1[++top]=p;
            s2[top]=0;
            p=p*2;
        }
        if(top==0) b=0;
        else if(s2[top]==0)
        {
            p=s1[top]*2+1;
            s2[top]=1;
        }
        else
        {
            p=s1[top];
            top--;
            cout<<T.bitTree[p]<<" ";
            T.bitTree[p]='0';
        }
    }while(b!=0);
    return 1;
}

链式形式


递归形式
先序遍历
void PreOrder(BiTree T){
	if(T != NULL){
		visit(T);	//访问根节点
		PreOrder(T->lchild);	//递归左子树
		PreOrder(T->rchild);	//递归右子树
	}
}
中序遍历
void InOrder(BiTree T){
	if( T != NULL){
		InOrder(T->lchild);	//递归左子树
		visit(T);	//访问根节点
		InOrder(T->rchild);	//递归右子树
	}
}

后序遍历
void PostOrder(BiTree T){
	if(T != NULL){
		PostOrder(T->lchild);	//递归左子树
		PostOrder(T->rchild);	//递归右子树
		visit(T);	//访问根节点
	}
}

非递归形式–运用栈来完成

中序遍历
//用栈来进行实现——中序遍历——
void InOrder2(BiTree T){
	InitStack(S);
	BiTree *p = T;	//p是遍历指针 
	while( p || !isEmtry(S)){	//栈不空 
		if(p){	//p存在就往左 
			Push(S , p);	//结点入栈 
			p = p->lchild;	//左孩子不空,一路往左走 
		}
		else{	//出栈,并转向出栈结点的右子树 
			Pop(S ,p);	//栈顶元素出战 
			visit(p);	//访问根节点 
			p = p->rchild;	//向右子树走,p赋值为当前结点的右孩子			
		}
	}
} 
后续遍历
void PostOrder2(BiTree T){
	InitStack(S);
	BiTree *P = T;
	while( p || !isEmtry(S)){
		if(p){
			Push(S , p);
			p = p->lchild;
		}
		else{
			Pop(S ,p );
			p = p->rchild;
			visit(p);
		}
	}
}
先序遍历
void PreOrder2(BiTree T){
	InitStack(S);
	BiTree *p = T;
	while( p || !isEmtry(S)){
		if(p){
			visit(p);
			Push(S , p );
			p = p->lchild;
		}
		else{
			Pop( S , p );
			p = p->rchild;
		}
	}
}

层次遍历

从上到下,从左到右

//用队列来实现层次遍历
void LevelOrder(BiTree T){
	InitQueue(Q);	//初始化辅助队列
	BiTree *p = T;
	EnQueue( Q , T );	//根节点入队
	while(!isEmtry(Q)){
		DeQueue(Q , p);		//结点出队 
		visit(p);			// 访问结点 
		if(p->lchild != NULL){
			EnQueue(Q , p->lchild);
            //左子树不空,则左子树结点入队 
		}
		if(p->rchild != NULL){
			EnQueue(Q , p->rchild);
            //右子树不空,则右字数结点入队 
		}
	}
} 

从下到上,从右到左遍历

//借用栈来存储结点,先存从上到下、从左到右的结点,再通过栈输出就是从下到上,从右到左。
void LevelOrder_STree(BiSTree &T){
	Stack S;	//栈用来存放二叉树的结点 
	SeQueue Q;	//队列用来存放指针 
	if( T!=NULL){
		InitStack(S);
		InitQueue(Q);
		EnQueue(Q ,T);
		while ( !IsEmtry(Q) == false){	//层次遍历 
			DeQueue(Q ,p);
			Push(S ,p);		//出队。入栈 
			if(p->lchild != NULL){
				EnQueue(Q , p->lchild);
			}
			if(p->rchild != NULL){
				EnQueue(Q , p->rchild);
			}
		}
		while( IsEmtry(S) == false){
			Pop(S , p);
			visit(p->data);
		}
	}
}

typedef struct{
	int data[MaxSize];
	struct *rear , *front;
}SqQueue;

int BiTree_length(BiTree T){
	if(!T)	//树空,则返回0
		return 0; 
	InitQueue(Q);
	SqQueue Q;	//设置队列Q
	int front = -1 , rear = -1;	//队列最左最右 
	int last = 0 , level = 0;	//last指向最右边的结点,level指层数
	Q.data[++rear] = T;
	BiTree p;
	while(front < rear){	//队不空,则循环
		p = Q.data[Q.rear];	//队列元素出队,即正在访问的结点
		if(p->lchild)	//左孩子入队
			Q.data[++Q.rear] = p->lchild;
		if(p->rchild)	//右孩子入队
			Q.data[++Q.rear] = p->rchild;
		if( front == rear){	//处理该层的最右结点
			level++;	//层数+1
			last = rear;	//last指向下一层	
		}
	}
	return level; 
}

int BiTree_Length2( BiTree T ){
	if(T == 0)
		return 0;
	int leftLength = BiTree_length(T->lchild);
	int rightLength = BiTree_length(T->rchild);
	if(leftLength > rightLength)
		return leftLength+1;
	else
		return rightLength+1;
}


线索二叉树

结点结构

#define MaxSize 100
typedef struct ThreadNode{
	ElemType data;
	struct ThrearNode *lchild , *rchild;	//左右孩子指针
	int ltag , rtag;	//左右线索标志
}ThreadNode , *ThreadTree;


构造线索二叉树

中序遍历构造

void InThread_Tree(ThrearTree &p , ThrearTree &pre){
	if( p != NULL ){
		InThread_Tree(p->lchild , pre);
		if(p->lchild == NULL ){
		//左子树为空,建立前驱
			p->lchild = pre;
			p->ltag = 1;
		}
		if(p->rchild == NULL || pre!= NULL){
		//建立前驱节点的后续线索
			p->rchild = pre;
			p->rtag = 1;
		}
		pre = p;
		InThread_Tree(p->rchild , pre);
	}
}

void CreateThread_Tree(ThreadTree T){
	ThreadTree pre = NULL;
	if(T != NULL){	//非空线索二叉树线索化
		InThread_Tree(T , pre);	//线索化二叉树
		p->rchild = NULL;	//处理最后一个结点
		p->rtag = 1;
	}
}

前序遍历构建

void PreTread_Tree(ThreadTree &p , TreadTree &pre){
	if(p!=NULL){
		if(p->lchild == NULL){
			p->lchild = pre;
			p->ltag = 1;
		}
		if( pre!= NULL || p->rchild == NULL){
			p->rchild = pre;
			p->rtag = 1;
		}
		pre = p;
		PreTread_Tree(p->lchild , pre);
		PreTread_Tree(p->rchild , pre);
	}
}

void CreateTread_Tree(ThreadTree T ){
	ThreadTree pre ==NULL;
	if(T != NULL){
		PreTread_Tree(T , pre);
		p->rchild = NULL;
		p->rtag = 1;
	}	
}

后序遍历

void PostTread_Tree(TreadTree &p , TreadTree &pre){
	if( p!= NULL){
		PostTread_Tree(p->lchild , pre);
		PostTread_Tree(p->rchild , pre);
		if(p->lchild == NULL){
			P->lchild = pre;
			p->ltag = 1;
		}
		if(p->rchild == NULL || pre != NULL){
			p->rchild = pre;
			p->rtag = 1;
		}
		pre = p;
	}
}
//创建线索二叉树
void CreateTread_Tree( ThreadTree T){
	ThreadTree pre = NULL;
	if(T != NULL){
		PostTread_Tree( T , pre);
		p->rchild = NULL;
		p->rtag = 1;
	}
}

不带头结点的中序遍历

void FirstNode(ThreadTree *p){
	while(T->ltag == 0)
		p = p->lchild;//最左下节点
}

void NextNode(ThreadTree *p){
	while(T->rtag == 0)
		return FirsrNode(p->rchild);
	else
		p = p->rchild;
		//若是p->rtag=1就直接返回后继线索
}

void InOrder(TreadNode *T){
	for(ThreadNode *p = FirstNode(T); p!=NULL ; p = NextNode(p)){
		visit(p);
	}
}

二叉排序树


结点结构

typedef struct BSTNode{
	int key;
	struct BSTNode *lchild;	//左孩子
	struct BSTNode *rchild;	//右孩子
}BSTNode , *BSTree;

基本操作


构建二叉树

void Creat_BST( BiTree T , int str[] , int n){
	T = NULL;
	int i = 0;
	for( i ; i< n ; i++){
		BSTree_Insert(T , str[i]);
	}
}

初始化

//生产一个结点并进行初始化
int BSTNode_ctreat( int data){
	BSTNode *t = (BSTNode*)malloc(sizeof(BSTNode));
	if(t == NULL)
		exit(0);
	t->data = data;
	t->lchild = NULL;
	t->rchild = NULL;
	return t;
}

找key结点

void Search_keynode(BSTree , T , int key){
	while( T->key != key && T != NULL ){
		if(key < T->key)
			T->lchild;
		else
			T->rchild;
	}
	return T;
}

找key值

void BSTree_Search_key(BSTree T , int key){
	if( T == NULL)
		return 0;
	if( T->key > key)
		return BSTree_Search_key(T->lchild , key);
	else if(T->key < key)
		return BSTree_Search_key(T->rchild , key);
}

插入操作

int BSTree_Insert(BiTree T , int key){
	if(T == NULL){		//原树为空,新插入的记录为根节点 
		T= (BSTree *)malloc(sizeof(BSTree));
		T->key = k;
		T->lchild = T-rchild = NULL;
		return 1; 	//输出1,插入成功 
	}
	else if( k == T-key)	//树中存在相同关键字,插入失败
		return 0;
	else if( k > T->key){	//插入到左子树 
		return BSTree_Insert(T->lchild , k);
	} 
	else{		//插入到右子树 
		return BSTree_Insert(T->rchild , k);
	}	
}

删除操作

void Delete(BSTree &T, int key)
{
	if (T == NULL)
	{
		exit(1);  //空树直接报错
	}
	BSTNode *p;
	BSTNode *f = NULL;
	BSTNode *q, *s;
	if (Search(T, key, NULL, &p)) //确实存在值为key的节点,则p指向该节点
	{
 
		if (NULL == p->lchild && NULL != p->rchild)  //无左孩子,有右孩子
		{
			q = p->rchild;
			p->data = q->data;    //因为两个节点之间本质的不同在于数据域的不同,而与放在哪个地址没有关系
			p->rchild = q->rchild;
			p->lchild = q->lchild;
			free(q);
		}
		else if (NULL == p->rchild && NULL != p->lchild)  //无右孩子,有左孩子
		{
			q = p->lchild;
			p->data = q->data;
			p->rchild = q->rchild;
			p->lchild = q->lchild;
			free(q);
		}
		else if (NULL != p->rchild && NULL != p->lchild) //既有左孩子,又有右孩子
		{
			q = p;
			s = p->lchild;   //找左孩子的最右孩子
			while (s->rchild)
			{
				q = s;
				s = s->rchild;
			}
			p->data = s->data;
 
			if (q != p)
			{
				q->rchild = p->lchild;
			}
			else
			{
				q->lchild = s->lchild;
			}
			free(s);
		}
		else
		{
			if (T == p)   //只有一个根节点
			{
				free(T);
				T = NULL;
				return;
			}
 
			BSTNode* parent = FindParent(T, p);
			if (parent->lchild == p)
			{
				parent->lchild = NULL;
			}
			else
			{
				parent->rchild = NULL;
			}
			free(p);
		}
	}
}

查询key

bool Search(BSTree T, int key, BSTree f, BSTree *p) {
//查找成功时,p指向值为key的节点。如果查找失败,则p指向遍历的最后一个节点
	if (!T)
	{
		*p = f;
		return false;
	}
	if (T->data == key)  //查找成功,直接返回
	{
		*p = T;
		return true;
	}
	else if (T->data < key)
	{
		return Search(T->rchild, key, T, p);
	}
	return Search(T->lchild, key,T, p);
}

找父节点

BSTNode* FindParent(BSTree bst, BSTNode *child)
{
	if (NULL == bst)
	{
		return NULL;
	}
 
	if (bst->lchild == child || bst->rchild == child)
	{
		return bst;
	}
	else if(NULL != bst->lchild)
	{
		FindParent(bst->lchild, child);
	}
	else if (NULL != bst->rchild)
	{
		FindParent(bst->rchild, child);
	}
}

算法

查找结点i和j的公共祖先结点

int Ancestor(STree &T , int i  , int j){
	if(T[i] != '#' && T[j] != '#'){
		while( i != j ){	//结点同时存在 
			if(i>j)		//两个编号不同时循环 
				i = i/2;	//向上找i的祖先 
			else
				j = j/2;	//向上找j的祖先 
		}
		return T[i];
	}
}

判定是否为完全二叉树

思想:利用层次遍历,让n个结点入队;当遇到空结点时,查看后面是否有非空结点;若有则不是完全二叉树(完全二叉树一个空结点后全是空结点)

bool IsCompare(BiSTree T){
//本算法判定给定的二叉树是否为完全二叉树 
	if(!T)
		return 1;	//空树为满二叉树 
	InitQueue(Q); 
	BiSTree *p = T;
	EnQueue(Q , p);
	while(!isEmpty(Q) ){
		DeQueue(Q , p);
		if( !p){
			EnQueue(Q , p->lchild);
			EnQueue(Q , p->rchild);
		}
		else{	//结点没有子树 
			while( !isEmpty(Q)){
				DeQueue(Q , p);		//将结点拉出,查看是否有后续结点 
				if(p)		//结点为空,则返回0,说明是非完全二叉树 
					return 0; 
			}
		}
	}
	return 1;
}

求高度

非递归方式
思路:借用顺序队来层次遍历树,找到树是最大深度

typedef struct{
	int data[MaxSize];
	struct *rear , *front;
}SqQueue;

int BiTree_length(BiTree T){
	if(!T)	//树空,则返回0
		return 0;
	SqQueue Q[MaxSize];	//设置队列Q
	int front = -1 , rear = -1;	//队列最左最右 
	int last = 0 , level = 0;	//last指向最右边的结点,level指层数
	Q.data[++rear] = T;
	BiTree p;
	while(front < rear){	//队不空,则循环
		p = Q.data[Q.rear];	//队列元素出队,即正在访问的结点
		if(p->lchild)	//左孩子入队
			Q.data[++Q.rear] = p->lchild;
		if(p->rchild)	//右孩子入队
			Q.data[++Q.rear] = p->rchild;
		if( front == last){	//处理该层的最右结点
			level++;	//层数+1
			last = rear;	//last指向下一层	
		}
	}
	return level; 
}

//递归算法
int BiTree_Length2( BiTree T ){
	if(T == 0)
		return 0;
	int leftLength = BiTree_length2(T->lchild);
	int rightLength = BiTree_length2(T->rchild);
	if(leftLength > rightLength)
		return leftLength+1;
	else
		return rightLength+1;
}

二叉链表求双结点个数

思想:建立模型
1.当b = NULL 时,f(b) = 0
2.当*b为双分支结点,则f(b) = f(b->lchild)+f(b->rchild)+1;
3.其他情况时,f(b) = f(b->lchild)+f(b->rchild)

int DsonNodes(BiTree T){
	if(T == NULL)
		return 0;
	else if(T->lchild != NULL && T->rchild != NULL)	//双分支结点
		return DsonNodes(T->lchild) + DsonNodes(T->rchild) + 1;
	else if
		return DsonNode(T->lchild) + DsonNodes(T->rchild);
}

链式二叉树结点左右互换

思想:用递归来交换
先交换T结点左右子树,再交换结点T的右孩子左右子树,最后交换T结点的左子树,当结点为空时递归结束

void SwapTree(BiTree T){
//通过递归将二叉树的左右节点互换
	if(T != NULL){
		BiTree *p = T->lchild;
		T->lchild = T->rchild;
		T->rchild = p;
		SwapTree(T->lchild);	//递归交换左子树
		SwapTree(T->rchild);	//递归交换右子树
	}
	else
		return;
}

求二叉树中的第k个结点的值(1<k<n)

求先序遍历的第k个结点的值
思想:通过递归模拟先序二叉树,到第k个结点时输出T的值

int i = 1;
int PreNode_k_Value(BiTree T , int k){
//本算法查找二叉树先序遍历序列中第k个结点的值
	if(	T == NULL)
		return '#'	//空结点 , 返回特殊字符
	if( i == k)
		return b->data;
	i++;	//下一个结点
	int value = PreNode_k_Value(T->lchild , k);	//在左子树里面查找 
	if(value != '#')
		return value;
	value = PreNode_k_Value(T->rchild , k);		//在右子树里面查找 
		return value;
}

删除值为X的结点的子树

思想:用层序遍历来进行,找到父节点,再用后序遍历删除左右子树;
删除操作:删除以元素x的子树,只能删除其左、右子树,就可以释放值为x的根节点

void DeleteTree(BiTree &T){
//删除操作
	if(T){
		DeleteTree(T->lchild);
		DeleteTree(T->rchild);
		free(T);
	}
} 
//在二叉树中找到值为x的结点,并删除他的子树 
void Search_x(BiTree T , int x){
	BiTree Q[];		//Q是用来存放二叉树指针的队列,容量足够大 
	if(T){
		if(T->data == x){
			DeleteTree(T);
			exit(0);
		}
		InitQueue(Q);
		EnQueue(Q , T);
		while(!isEmpty(Q)){
			DeQueue(Q , p);
			if( p->lchild ){	//若左子树非空 
				if(p->lchild->data == x){	//左子树符合则删除左子树
					DeleteTree(p);
					p->lchild = NULL;	//父节点的左子女置空
				}
				else
					EnQueue(Q , p->lchild);	`//左子女入队
			}
			if(p->rchild){	//若右子树非空
				if(p->rchild->data == x){	//右子树符合则删除右子树
					p->rchild =NULL;	//父节点的右子女置空
				}
           		else
					EnQueue(Q , p->rchild);	`//右子女入队
			}
		}
	}
}

二叉树中任意指针p和q的公共祖先节点r

结点结构为(llink, info , rlink)的二叉树
思想:采用后序非递归算法来求,栈中存放该结点的祖先

typedef struct {
	BiTree data;
	int tag;	//tag = 0 证明左子女被访问,tag = 1证明右女子被访问 
}stack;

stack s[] , s1[];
//查找p和q的公共祖先节点,设p 在q的左边 
BiTree Ancestor(BiTree RooT , BiNode *p , BiNode *q){
	top = 0;
	T = ROOT;
	while( top > 0 || T!= NULL ){ 
		while( T!= NULL){	//先遍历左边,先使得找到p
			s[++top] = T;
			s[top].tap = 0;
			T = T->lchild;
		}
		while( top!=0 || s[top].tag == 1 ){	//查找是否找到p值和q值 
			if(s[top].data == p){
				for(int i =1 ; i <= top ; i++ ){
					s1[i] = s[i];
					top1 = top;
				}
			}
			if(s[top].data == q){
				for(int i =1 ; i < top ; i++){
					for( int j = top ; j > 0 ; j--){
						if(s1[i].data == s[j].data)
							return s[i].data;
					}
				}
				top--;		//退栈 
			}
		}
		if( top != 0){		//沿右分支向下遍历 
			S[top].tag = 1;
			T = T->rchild;
		}
	}
	return NULL;
} 

求二叉树宽度——二叉树最多结点数

思想:用层序遍历的方法求出所有结点的层次,并将所有节点和对应的层次放在一个队列中。然后通过扫描队列求出各层的节点总数,最大的层结点总数即为二叉树的宽度

typedef struct{		//定义一个队列 存放二叉树结点和层数
	BiTree data[MaxSize];	//存放二叉树结点
	int level[MaxSize];		//存放二叉树层数
	int front , int rear;
} Queue;

int BTWidth(BiTree T){
	BiTree	p;
	int k , max , i ,n;
	Q.front = Q.rear = -1;	//队列为空
	Q.rear++;
	Q.data[Q.rear] = T;
	Q.level[Q.rear] = 1;
	while( Q.front < Q.rear ){
		Q.front++;	//出队		
		p = Q.data[Q.front];	//出根节点指针入队 
		k = Q.level[Q.rear];	//记录层数 
		if( p->lchild != NULL){		//左孩子进入队列 
			Q.data[Q.rear] = p->lchild;
			Q.level[Q.rear] = k+1;
		} 
		if( p->rchild != NULL){		//右孩子进入队列 
			Q.rear++;
			Q.data[Q.rear] = p->rchild;
			Q.level[Q.rear] = k+1;
		}
	} 	
	max = 0 , i = 0;	//max保存同一层最多的结点个数 
	k = 1;				//k表示第一层开始查找 
	while( i < Q.rear){	//i扫描队中所有元素 
		n = 0;			//n统计第k层的元素个数 
		while( i <= Q.rear && Q.level[i] == k){
			n++;
			i++;
		}
		k = Q.level[i];
		if(n>max)
			max = n;	//保留最大n 
	}
	return max;
} 

满二叉树通过先序序列知道后序序列

一般二叉树仅根据先序序列无法确定另外一个遍历序列,但满二叉树可以(因为任意一个节点的左右子树都有相等的结点数)

void Pre_to_Post(ElemType pre[] , int l1 , int h1 , ElemTyle post[] , int l2 , int h2){
	int half;
	if( h1 >= l1){
		post[h2] = pre[l1];
		Pre_to_Post( pre , l1+1 , h1+half , post , l2 , l2+half-1);		//转换左子树
		Pre_to_Post( pre , l1+half+1 , h1 , post , l2+half , h2-1); 	//转换右子树
	} 
}

//证明
	char *pre = "ABCDEFG";
	char post[MaxSize];
	Pre_to_Post( pre , 0 , 6 , post , 0 , 6);
	printf("后序序列:");
	for(int i = 0 ; i <= 6 ;i++ )
		printf("%c" , post[i]);
	printf("\n");

将二叉树的叶子结点连成单链表

LinkedList head , pre = NULL;	//全局变量 
void InOrder( BiTree T){
	if(T != NULL){
		InOrder(T->lchild);		//中序遍历左子树 
		if( T->lchild == NULL && T->rchild == NULL){	//叶子结点 
			if( pre == NULL){	//处理第一个结点 
				head = T;
				pre = T;
			}
			else{	//将叶节点连入链表 
				pre->rchild = T;	
				pre = T;
			}
		}
		InOrder(T->rchild);		//中序遍历右子树
		pre->rchild = NULL;		//设置链表尾 
	}
	return head;
}

判断两个二叉树是否相似

相似条件: 1.空树且仅有一个根节点

​ 2.两个子树左子树与右子树相似

int Similar(BiTree T1 , BiTree T2){
	int Lefts , Rights; 
//用递归的算法判断两个二叉树是否相似 
	if(	T1 == NULL && T2 == NULL)
		return 1;		//两个都是空树,说明相似
	if( T1 == NULL || T2 == NULL)
		return 0;		//其中一个是空树,不相似 
	else{
		Lefts = Similar(T1->lchild , T2->lchild);
		Rights = Similar(T1->rchild , T2->rchild);
		return Lefts && Rights;
	}
}

中序线索二叉树查找指定节点在后序的前驱结点的算法

void InPostPre(BiThrTree T , BiThrTree p){
//在中序线索二叉树T中,求指定结点p在后序下的前驱结点q
	BiThrTree q;
	if(p->rtag = 0)		//若是p有右子女,则右子女是其后续前驱	 
		q = p->rchild;
	if(p->ltag = 0)		//若是p有左子女,则左子女是其后续前驱
		q = p->lchild;
	else if(p->lchild == NULL) 	//p是中序序列第一节点,无后续前驱 
		q = NULL;
	else{		//顺着左线索向上招p的祖先,若存在,则再找祖先的左子女 
		while(p->ltag ==1 && p->lchild != NULL)
			p = p->lchild;
		if(p->ltag == 0)
			q = p->lchild;
		else
			q = NULL;
	}
	return q;
}

递归寻找值为x的结点的双亲结点p

void Findparent_p(BTNode *q , int x){
	if( q == NULL ){
		if( q->data == x ) 
			return p = NULL;
		else if( q->lchild != NULL && q->lchild->data == x)
			return p = q;
		else if( q->rchild != NULL && q->rchild->data == x)
			return p = q;
		else{
			Findparent_p(q->lchild , x);
			Findparent_p(q->rchild , x);		
		}
	} 
	return p = NULL;
} 

求总带权路径长度

我们用先序遍历来实现

typedef struct BiTNode{		//结点数据类型
	BiTNode *lchild , *rchild;
	int weight;		//深度
}BiTNode , *BiTree;

void WPL(BiTree Root){	//带权路径求总长
	return 	Wpl_PreOrder(Root , 0);	
}

int Wpl_PreOrder(BiTree Root int deep){
	int wpl = 0;
	if(Root->lchild == NULL && Root->rchild == NULL)
		wpl+= deep*root->weight;
	if(Root->lchild != NULL)
		Wpl_PreOrder(Root->lchild , deep+1);
	if(Root->rchild != NULL)
		Wpl_PreOrder(Root->rchild , deep+1);
	return wpl;
}

表达式二叉树转换为等价的中缀表达式二叉树

void BTreeTOE(BiTree *T){
	BTreeToExp(T , 1); 	//根的高度为1 
}

void BTreeToExp(BiTree *T , int deep){
	if(T == NULL)	//空树直接返回 
		return 0;
	else if(T->lchild == NULL && T->rchild)		//说明为叶子结点 
		return  printf("%s" , T-<data);
	else{
		if(deep > 1)	//若是深度超过了1,则说明有子表达式,加一层运算符 
			printf("(");
		BTreeToExp(T->lchild , deep+1);
		printf("%s" , T->data);
		BTreeToExp(T->rchild , deep+1);
		printf("%s" , T->data);
		if(deep > 1)	//若是深度超过了1,则说明有子表达式,加一层运算符 
			printf(")");
	}
}

求森林中的叶子结点数

用孩子兄弟表示法来进行储存
思想:若结点没有孩子,则它必是叶子结点,若总的叶子节点个数是孩子子树上的叶子数和兄弟子树上的叶节点个数之和

typedef struct node{
	int data;	//数据域
	struct node *firstchild , *nextchild;	//定义孩子和兄弟域
}node ,*Tree;

int Leavesnode(Tree T){
	if(T == NULL)	//若为空树,则叶子结点为0 
		return 0;
	if(T->firstchild == NULL)
		return 1+Leavesnode(T->nextchild);		//返回根节点数和其他兄弟子树中的结点数 
	else	//孩子子树和其他兄弟子树中的结点数之和 
		return Leavesnode(T->firstchild)+ Leavesnode(T->nextchild);
}

森林的深度

思想:递归算法,与树的差不多,高度为第一子女树高度+1和兄弟子树高度的大者

void Height(CSTree T){
	int heaght , h;
	if(T == NULL)
		return 0;
	if(T != NULL){
		height = Height(T->lchild);
		h = Height(T->rchild);
		if(height+1 > 0)
			return height+1;
		else
			return h;
	}
}

构建树的孩子兄弟链表

已知一棵树的层次序列和每个结点的度

#define MaxSize 100
void createCSTree_degree(CSTree &T , DataType e[] , int degree[] , int n){
//根据树节点的层次序列e[]和各结点的度degree[]构建树的孩子-兄弟链表
//参数n是树节点个数
	CSNode * pinter[MaxSize];
	int i , j ,k=0;
	for( i = 0 ; i < n ; i++){	//初始化 
		pointer[i]->data = e[i];
		pointer[i]->lchild = pointer[i]->rsiling = NULL;
	} 
	for( i = 0 ; i<n ; i++){
		d = degree[i];
		if(d){
			k++;		//K为子女结点序号 
			pointer->lchild = pointer[k];		//建立i与子女k间的链接 
			for( j =2 ; j<= d ;j++){
				k++;
				pointer[i]->rsiling = pointer[k];
			}
		}
	}
	T->pointer[0];
	return;
} 

求树的度

int TreeDegree(CSTree T) {
// 最大的孩子数
	int max=-1;
	int cnt=0;
	CSNode *child;
	if (!T) 
		return -1; 		//空树
	else if (!T->firstchild) 
		return 0; 		//只有一个根结点,度为0
	else {
		for (cnt=0,child = T->firstchild; child ; child=child->nextsibling) 
			cnt++;		 //求自己的度
		max = cnt;		 //当前的最大值
		for (child=T->firstchild; child; child = child->nextsibling) {
			cnt = TreeDegree(child);
			if (cnt>max) 
				max=cnt;
		}
		return max;
	}
}

输出T所有的边

void TreePrintEdge(CSTree T) {
	CSNode *p;
	for (p=T->firstchild; p; p=p->nextsibling) {
		printf("(%c,%c)\n", T->data, p->data); //输出T的孩子
		TreePrintEdge(p); //输出p的孩子
	}
}

双亲表示法–>孩子兄弟表达式

#define MAX_TREE_SIZE 50

typedef struct PTNode{
	TElemType data;
	int parent; //双亲的位置域
}PTNode;

typedef struct{
	PTNode nodes[MAX_TREE_SIZE];
	int r,n;
}PTree;

CSTree CreateCSTreeByPTree(PTree T) {
	CSNode *tmp[MAX_TREE_SIZE]; //创建一个辅助的数组,仿照PTree结点的位置存放
	CSNode *p, *q;
	int i,parent;
	
	if (T.n<=0) return NULL;
	for (i=0; i<T.n; i++) { //双亲表按层序存储
		//创建新结点
		p = (CSNode *)malloc(sizeof(CSNode)); 
		if(!p) 
			exit(OVERFLOW);
		//赋值
		p->data = T.nodes[i].data;
		p->firstchild=p->nextsibling=NULL;
		//连接
		parent=T.nodes[i].parent; //父亲
		if (parent!=-1) { //不是根结点
			if (tmp[parent]->firstchild==NULL) 
				tmp[parent]->firstchild=p; //第一个孩子
			else { //不是第一个孩子
				for (q=tmp[parent]->firstchild; q->nextsibling; 
					q=q->nextsibling) ; //找到最后一个孩子
				q->nextsibling = p; //连接
			}
		}
		tmp[i]=p;
	}
	
	return tmp[0];
}

判断是否是二叉排序树

思想:对于二叉排序树来说,中序遍历为递增有序序列,让其进行递增有序遍历,若一直保持前一个值小于后一个值,则为二叉排序树

Ketype pre = -23224;	//设置pre为全局变量,作为对比

void JudgeBST(BSTree T){
	int a , b;		//设置两个变量来进行对比
	if(T == NULL)
		return 1;
	else{
		a = JudgeBST(T->lchild);		//判断左子树是否是二叉排序树
		if( a == 0 || pre >= T->data)
			return 0;
		pre = T->data;
		b = JudgeBST(T->rchild);
		return b;
	}
}

查询结点在二叉排序树的第几层

思路:选用二叉排序树非递归查找算法;设二叉树用二叉链表存储。在二叉排序树中,查找一次就下降一层。所以查找次数=层数
用n保存查找次数,每查找一次,n就+1,直到找到对应节点

int Level(BSTree T , BSTree *p){
	int n=1;		//次数
	BSTree *pre = T;
	if(T!= NULL){
		while(p->data != pre->data){
            if( p->data > pre->data)
                pre = pre->rchild;
            else
                pre = pre->lchild;		
            }
			n++;
	}
	return n;
}

判断是否是平衡二叉树

int Judge_AVL(BSTree T , int &h ,int &balance){
//balance是平衡标记,h为高度 
	int a=0 , b=0 , c=0, d=0;
	if(T == NULL){
		h = 0;
		balance = 1;
	}
	else if( T->lchild == NULL && T->rchild == NULL ){
//仅有根节点,则高度为1
		h = 1;
		balance = 1;
	}
	else{
		Judge_AVL(T->lchild , a , b);
		Judge_AVL(T->rchild , c , d);
		h = (b > d ? b : d)+1;
		if( abs( b - d )<2)		//若子树高度差的绝对值<2,则看左右子树是否平衡 
			balance = a && c	//&&为逻辑与,即左右子树都平衡的话,二叉树平衡 
		else
			balance = 0;
	}
}

查找二叉排序树最大、最小关键值

思路:二叉排序树中最左节点最小,最右节点最大;一直向左和向右遍历直到找到叶子结点即找到最小、最大结点

//最大关键值
void Maxvalue_BST(BSTree *T){
	BSTree *p = T;
	while( p->rchild != NULL){
		p = p->rchild;
	}
	return p->data;
}

//最小关键值
void Minvalue_BST(BSTree *T){
	BSTree *p = T;
	while( p->lchild != NULL){
		p = p->lchild;
	}
	return p->data;
}

从小到大输出二叉排序树中值不小于k的关键字

思路:二叉排序树中右子树的节点值均大于根节点值,且所有左子树结点都小于根节点。所以让其先遍历右子树,在访问根节点,后遍历左子树
(或运用中序遍历+栈也可以实现)

void OutPut( BSTree T , int k ){
	if(T == NULL)	//空树 
		return 0;
	if(T->lchild != NULL)
		OutPut(T->rchild , k);	//递归输出右子树的结点 
	if(T->data == k)
		printf("%d" , T->data);	//只输出大于或等于k的节点值 
	if(T->rchild != NULL)
		OutPut(T->lchild , k);	//递归输出左子树的结点 
}

找二叉排序树上第k小的结点

额外增加一个count记录结点的数量

void Search_small(BSTree T , int k){
//在T上寻找第k小的元素,返回其所在的结点,则让k从11开始计算
//树节点中增加一个count数据成员,储存结点数
	if( k <1 || k >T->count )
		return NULL;
	if(T->lchild == NULL){		
	//若是T->lchild 为空,则有两种情况,第一种是k=1 ,则根节点为第k个 		
		if(k == 1)
			return T;
		else	//第二种情况是k != 1,则让其进行递归 
			Search_small(T->rchild , k);
	} 
	if(T->lchild != NULL ){	
	//若左子树不空,则有两种情况,首先是当T->lchild->count是第k-1个最小的 ,则返回T
		if( T->lchild->count == k-1 )
			return T;
	//若 T->lchild->count不是第k-1个最小的,则正常遍历
		if( T->lchild->count > k-1)
			return Search_small(T->lchild , k);
		if( T->lchild->count < k-1)
			return Search_small(T->rchild , k-(T->lchild->count+1)); 
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值