`
hao3100590
  • 浏览: 128631 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

二叉树基本操作大全

阅读更多

1.二叉树的基本操作

这里我有一个疑问:

 

在使用构造函数的时候,传参数的问题?

开始我是这么理解的------只使用指针(其实指针本身就是一个地址,相当于引用,也会改变root建立起二叉树),而2指针的引用,相当于就是对记录了指针的地址,采用了二次引用,其实是没有必要的,一次就够了。但是实际上用的时候并不是这样?根本不能建立二叉树,原因是因为开始指针指向的是一个不确定的位置?然后我又实验了,分配空间先,但是还是不行?所以不知道为什么一定要使用双重指针或指针引用?不知哪位高人能解答之,谢谢了

就是这样void creatTree(Node<T>* root);

 

 

//声明类BiTree及定义结构BiNode,文件名为bitree.h
#ifndef BITREE_H
#define BITREE_H
template <class T>
struct Node   //二叉树的结点结构
{
  T data;       
  Node<T> *lchild, *rchild;
};
//定义队列或栈空间大小
const int SIZE = 100;

template <class T>
class BiTree
{
public:
    BiTree( );             //构造函数,初始化一棵二叉树,其前序序列由键盘输入(输入序列是前序遍历顺序)
    BiTree(T* a, int n);	 //构造函数,输入序列是层序序列(非递归建立)
    ~BiTree();         //析构函数,释放二叉链表中各结点的存储空间
    Node<T>* getRoot();  //获得指向根结点的指针
    void preOrder(Node<T> *root);     //前序遍历二叉树
    void inOrder(Node<T> *root);      //中序遍历二叉树
    void postOrder(Node<T> *root);    //后序遍历二叉树
    void leverOrder(Node<T> *root);   //层序遍历二叉树
    void nrPreOrder(Node<T> *root);   //前序遍历二叉树(非递归)
    void nrInOrder(Node<T> *root);    //中序遍历二叉树(非递归)
    void nrPostOrder(Node<T> *root);  //后序遍历二叉树(非递归)
    
    //基本操作
    Node<T>* searchNode(T x);					//寻找值为x的节点
    int biTreeDepth(Node<T>* root);								//二叉树深度
    Node<T>* getParent(Node<T>* root, T x);				//如果存在值为data的节点,返回其父节点
    Node<T>* getLeftSibling(Node<T>* root, T x);	//获取左兄弟
    Node<T>* getRightSibling(Node<T>* root, T x);	//获取右兄弟
    int leafCount(Node<T>* root);									//叶子个数
    int nodeCount(Node<T>* root);									//节点个数
    void deleteSibTree(Node<T>* root, T x);				//删除节点x为根节点的子树
    
private:
    Node<T> *root;         //指向根结点的头指针
    //1.使用双指针(指向指针的地址,这样就不在是拷贝,相当于一个引用)
    //void creatTree(Node<T> **root);		 //有参构造函数调用(根地址的地址,也可指针的引用)
    //2.使用引用(别名,可以直接对root操作)
    void creatTree(Node<T>* &root);
    //3.使用返回
    //Node<T>* creatTree();
   //4.只使用指针(其实指针本身就是一个地址,相当于引用,也会改变root建立起二叉树)
    //而2指针的引用,相当于就是对记录了指针的地址,采用了二次引用,其实是没有必要的,一次就够了
    //但是实际上用的时候并不是这样?根本不能建立二叉树,原因是因为开始指针指向的是一个不确定的位置?
    //然后我又实验了,分配空间先,但是还是不行?所以不知道为什么一定要使用双重指针或指针引用?不知哪位高人能解答之,谢谢了
    //void creatTree(Node<T>* root);
    
    void createTree(Node<T>* &root, T* a, int n);//非递归建立二叉树
    void search(Node<T>* root, T x, Node<T>* &p);	//搜索
    void releaseTree(Node<T> *root);   //析构函数调用 
};
#endif

 2.基本操作实现

 

#include <iostream>
#include "bitree.h"
using namespace std;

//构造函数,初始化一棵二叉树,其前序序列由键盘输入
template <class T>
BiTree<T>::BiTree( ){
	//creatTree(&root);	//1.双指针(指向指针的地址,故而使用取地址操作符,取出指针root的地址)
	creatTree(root);		//2.root的引用
	//root = creatTree();	//3.返回(实际上是this->root = createTree())
} 

template <class T>
BiTree<T>::BiTree(T* a, int n){
	createTree(root, a, n);
}          

//析构函数,释放二叉链表中各结点的存储空间
template <class T>
BiTree<T>::~BiTree(){
	releaseTree(root);
}
	        
//获得指向根结点的指针
template <class T>
Node<T>* BiTree<T>::getRoot(){
	return root;
}

//前序遍历二叉树 
template <class T>
void BiTree<T>::preOrder(Node<T> *root){
	if(root){
		cout<<root->data<<" ";
		preOrder(root->lchild);
		preOrder(root->rchild);
	}
}    

//中序遍历二叉树
template <class T>
void BiTree<T>::inOrder(Node<T> *root){
	if(root){
		inOrder(root->lchild);
		cout<<root->data<<" ";
		inOrder(root->rchild);
	}
}    

//后序遍历二叉树
template <class T>
void BiTree<T>::postOrder(Node<T> *root){
	if(root){
		postOrder(root->lchild);
		postOrder(root->rchild);
		cout<<root->data<<" ";
	}
}  

//层序遍历二叉树
template <class T>
void BiTree<T>::leverOrder(Node<T> *root){
	int front = 0;
	int rear = 0;  //采用顺序队列,并假定不会发生上溢
	Node<T>* queue[SIZE];//存放结点指针的数组
	Node<T>* t;							//临时结点指针
	if(root == NULL) return;
	else{
		queue[rear++] = root;
		while(front != rear){
			t = queue[front++];
			if(t) cout<<t->data<<" ";
			if(t->lchild) queue[rear++] = t->lchild;
			if(t->rchild) queue[rear++] = t->rchild;
		}
	}
}

//层序遍历二叉树(利用循环队列)
/*
template <class T>
void BiTree<T>::leverOrder(Node<T> *root){
	int front = 0;
	int rear = 0;  //采用顺序队列,并假定不会发生上溢
	Node<T>* queue[SIZE];//存放结点指针的数组
	Node<T>* t;							//临时结点指针
	if(root == NULL) return;
	else{
		queue[rear] = root;
		rear = (rear+1)%SIZE;
		while(front != rear){
			t = queue[front];
			front = (front+1)%SIZE;
			if(t) cout<<t->data<<" ";
			if(t->lchild){ queue[rear] = t->lchild; rear = (rear+1)%SIZE;}
			if(t->rchild){ queue[rear] = t->rchild; rear = (rear+1)%SIZE;}
		}
	}
	
}*/

//-------------------------建立树的三种参数设置方法---------------------------------

//有参构造函数调用(前序递归建立树,输入顺序也必须是前序)
/*
template <class T>
void BiTree<T>::creatTree(Node<T> **root){
	T ch;
	cout<<"请输入创建一棵二叉树的结点数据"<<endl;
	cin>>ch;
	if(ch == "#") *root = NULL;
	else{
		*root = (Node<T>*)new Node<T>; //*root = new Node<T>;不过前面写法更好
		(*root)->data = ch;
		creatTree(&(*root)->lchild);
		creatTree(&(*root)->rchild);
	}
}   
*/

/*
template <class T>
Node<T>* BiTree<T>::creatTree(){
	Node<T>* root;
	T ch;
	cout<<"请输入创建一棵二叉树的结点数据"<<endl;
	cin>>ch;
	if(ch == "#") root = NULL;
	else{
		root = new Node<T>;
		root->data = ch;
		root->lchild = creatTree();
		root->rchild = creatTree();
	}
	return root;
}  
*/

template <class T>
void BiTree<T>::creatTree(Node<T>* &root){
	T ch;
	cout<<"请输入创建一棵二叉树的结点数据"<<endl;
	cin>>ch;
	if(ch == "#") root = NULL;
	else{
		root = new Node<T>;
		root->data = ch;
		creatTree(root->lchild);
		creatTree(root->rchild);
	}
}  

template <class T>
void BiTree<T>::createTree(Node<T>* &root, T* s, int n){
		Node<T>* queue[SIZE];
		Node<T> *p, *m;
		int rear = 0, front = 0;
		if(s[0] == "#"){ 
			root = NULL;
	  }else{
	    root = new Node<T>;
	    root->data = s[0];
	    queue[rear++] = root; 
	  }
    int i=1;//注意不管出不出栈,或者是空节点,i都要往前,出一次栈对应i前进2
    while(front != rear && i<n)
   	{
      p = queue[front++];
      if(s[i] != "#"){
      	//出栈后遍历后面连续两个左右节点
         m = new Node<T>;
         m->data = s[i++];
         p->lchild = m;
         queue[rear++] = m;
         if(s[i] != "#"){ //右
           m = new Node<T>;
           m->data = s[i++];
           p->rchild = m;
           queue[rear++] = m;
         }else{ 
         	 i++;
         	 p->rchild = NULL;
         }
      }else{
      	 i++;
         p->lchild = NULL;
         if(s[i] == "#"){
         		p->rchild = NULL;
         		i++;
         }else{
         		m = new Node<T>;
            m->data = s[i++];
            p->rchild = m;
            queue[rear++] = m;
         }
      }
      //cout<<"----"<<i<<endl;
    }
}

//析构函数调用 
template <class T>
void BiTree<T>::releaseTree(Node<T> *root){
	if(root){
		//递归删除,先释放左右结点在根结点,不能是先根在左右
		releaseTree(root->lchild);
		releaseTree(root->rchild);
		delete root;
	}
}


	
//前序遍历二叉树(非递归)
//它是在进栈的时候输出
template <class T>
void BiTree<T>::nrPreOrder(Node<T> *root){
	Node<T>* stack[SIZE];
	int top = 0;
	
	Node<T>* t = root;
	while(t || top != 0){
		//一直遍历左孩子,直到左孩子为空
		while(t){
			cout<<t->data<<" ";
			stack[top++] = t;
			t = t->lchild;
		}
		//如果左孩子为空了,然后出栈,遍历右结点
		if(top != 0){
			t = stack[--top];
			t = t->rchild;
		}
	}
}

//中序遍历二叉树(非递归)
//它是在出栈的时候输出
template <class T>  
void BiTree<T>::nrInOrder(Node<T> *root){
	Node<T>* stack[SIZE];
	int top = 0;
	
	Node<T>* t = root;
	while(t || top != 0){
		//一直遍历左孩子,直到左孩子为空
		while(t){
			stack[top++] = t;
			t = t->lchild;
		}
		//如果左孩子为空了,然后出栈,遍历右结点
		if(top != 0){
			t = stack[--top];
			cout<<t->data<<" ";
			t = t->rchild;
		}
	}
}  

//后序遍历二叉树(非递归)
//需要设置标志位,
template <class T>
void BiTree<T>::nrPostOrder(Node<T> *root){
	Node<T>* stack[SIZE];//存储树结点
	int flag[SIZE];			 //标记结点(0标记第一次出栈(未出),1标记第二次出栈(可出))
	int top = 0;
	Node<T>* t = root;
	while(t || top != 0){
		while(t){
			stack[top] = t;
			flag[top] = 0;
			top++;
			t = t->lchild;
		}
		//可以出栈
		while(top != 0 && flag[top-1] == 1){
			t = stack[--top];
			cout<<t->data<<" ";
		}
		
		if(top != 0){//第一次出栈(实际上并未出栈,只是标志位变为0)
			t = stack[top-1];
			flag[top-1] = 1;
			t = t->rchild;
		}else{
			t = NULL;	//这是结束条件,当top==0,在置t为空才能结束整个循环
		}
		
	}
}

//搜索节点x
template <class T>
void BiTree<T>::search(Node<T>* root, T x, Node<T>* &p){
	if(root){
		if(root->data == x){ p = root; return; }
		search(root->lchild, x, p);
		search(root->rchild, x, p);
	}
}

//寻找值为data的节点
template <class T>
Node<T>* BiTree<T>::searchNode(T x){
	Node<T>* r = NULL;
	if(root){
		search(root, x, r);
	}
	return r;
}				

//二叉树深度
template <class T>
int BiTree<T>::biTreeDepth(Node<T>* root){
	int hl, hr;
	if(root){
		hl = biTreeDepth(root->lchild);
		hr = biTreeDepth(root->rchild);
		return (hl>hr?hl:hr)+1;
	}
	return 0;
}						
    
//如果存在值为data的节点,返回其父节点
template <class T>
Node<T>* BiTree<T>::getParent(Node<T>* root, T x){
	Node<T> *q;
	if(!root) return NULL;
	else{
		//如果找到则返回
		if((root->lchild && root->lchild->data==x) || (root->rchild && root->rchild->data==x)){ 
			return root;
		//如果递归左子树没找到,到右子树上找(把递归当成普通的操作一样)
		}
		//如果左子树找到了返回双亲
		if(q = getParent(root->lchild, x)) return q;
		//如果左子树没找到,则到右子树找
		else if(q = getParent(root->rchild, x)) return q;
		//如果左右都没找到则返回空
		else return NULL;
	}
}

//获取左兄弟				
template <class T>
Node<T>* BiTree<T>::getLeftSibling(Node<T>* root, T x){
	if(!root) return NULL;
	else{
		if(root->lchild && root->lchild->data==x){//如果左子树是x,则必然不存在左兄弟
			return NULL;
		}
		
		if(root->rchild && root->rchild->data==x){//如果右子树是x,看是否存在左子树,存在则返回
			return root->lchild;
		}
		
		return getLeftSibling(root->lchild, x);
		return getLeftSibling(root->rchild, x);

	}
}			
    
//获取右兄弟
template <class T>
Node<T>* BiTree<T>::getRightSibling(Node<T>* root, T x){
	if(!root) return NULL;
	else{
		if(root->rchild && root->rchild->data==x){
			return NULL;
		}
		if(root->lchild && root->lchild->data==x){//获取右兄弟,则只需要关心左节点,如果左节点是x,在看左
			return root->rchild;
		}
		
		return getRightSibling(root->lchild, x);
		return getRightSibling(root->rchild, x);
	}
}		


//叶子个数
template <class T>
int BiTree<T>::leafCount(Node<T>* root){
	if(!root) return 0;
	else if(!root->lchild && !root->rchild){//如果是叶子节点,返回1
		return 1;
	}else{//如果左右子树不空,则递归遍历左右子树,结果就是左右子树叶子节点的和(递归加)
		return leafCount(root->lchild) + leafCount(root->rchild);
	}
}				

//节点个数	
template <class T>	
int BiTree<T>::nodeCount(Node<T>* root){
	if(!root) return 0;
	else{//递归调用加
		//节点个数=左子树节点个数+右子树节点个数+1
		return nodeCount(root->lchild) + nodeCount(root->rchild) + 1;
	}
}	

template <class T>
void BiTree<T>::deleteSibTree(Node<T>* root, T x){
	Node<T>* p;
	if(root){
		if(root->lchild && root->lchild->data==x){
			p = root->lchild;
			root->lchild = NULL;
			//递归删除p的左右子树
			releaseTree(p->lchild);
			releaseTree(p->rchild);
			delete p;
		}else if(root->rchild && root->rchild->data==x){
			p = root->rchild;
			root->rchild = NULL;
			//递归删除p的左右子树
			releaseTree(p->lchild);
			releaseTree(p->rchild);
			delete p;
		}else{//递归查找左右子树
			deleteSibTree(root->lchild, x);
			deleteSibTree(root->rchild, x);
		}
	}
}
				

 3.测试程序

 

//二叉树的主函数,文件名为bitreemain.cpp
#include<iostream>
#include<string>
#include"bitree.cpp"
using namespace std;

int main()
{	
	//注:BiTree<string> bt在输入的时候,必须是按照前序遍历的顺序输入节点,因为递归建立树的过程就是前序遍历
	//BiTree<string> bt;
	//string a[] = {"a", "b", "c", "#", "d", "#", "#", "#", "#", "#", "#"};
	//string a[] = {"a", "b", "c", "d", "#", "#", "#", "#", "#"};
	string a[] = {"a", "b", "c", "#", "d", "e", "f", "g", "#", "#", "#", "#", "#", "#", "#"};
	BiTree<string> bt(a, 15); //创建一棵树(按层序输入)
	Node<string>* root = bt.getRoot( );  //获取指向根结点的指针 

	cout<<"------前序遍历------ "<<endl;
	bt.preOrder(root);
	cout<<endl;
	cout<<"------中序遍历------ "<<endl;
	bt.inOrder(root);
	cout<<endl;
	cout<<"------后序遍历------ "<<endl;
	bt.postOrder(root);
	cout<<endl;
	cout<<"------层序遍历------ "<<endl;
	bt.leverOrder(root);
	cout<<endl;
	
	
	cout<<"------非递归前序遍历------ "<<endl;
	bt.nrPreOrder(root);
	cout<<endl;
	cout<<"------非递归中序遍历------ "<<endl;
	bt.nrInOrder(root);
	cout<<endl;
	cout<<"------非递归后序遍历------ "<<endl;
	bt.nrPostOrder(root);
	
	cout<<"\n---------基本操作----------"<<endl;
	Node<string>* t;
	cout<<"搜索b:";
	t = bt.searchNode("b");
	if(t) cout<<t->data<<endl;
	else cout<<"无"<<endl;
	if(t->lchild) cout<<"L:"<<t->lchild->data<<endl;
	if(t->rchild) cout<<"R:"<<t->rchild->data<<endl;
	
	cout<<"a的双亲:";
	t = bt.getParent(root, "a");
	if(t) cout<<t->data<<endl;
		else cout<<"无"<<endl;
	
	cout<<"b的双亲:";
	t = bt.getParent(root, "b");
	if(t) cout<<t->data<<endl;
		else cout<<"无"<<endl;
		
	cout<<"b的左兄弟:";
 	t = bt.getLeftSibling(root, "b");
  if(t) cout<<t->data<<endl;
  	else cout<<"无"<<endl;
  		
  cout<<"b的右兄弟:";
  t = bt.getRightSibling(root, "b");
  if(t) cout<<t->data<<endl;
 	else cout<<"无"<<endl;
  	
  cout<<"c的左兄弟:";
 	t = bt.getLeftSibling(root, "c");
  if(t) cout<<t->data<<endl;
  	else cout<<"无"<<endl;
  	
    cout<<"c的右兄弟:";
 		t = bt.getRightSibling(root, "c");
  	if(t) cout<<t->data<<endl;
  	else cout<<"无"<<endl;
	
	cout<<"二叉树深度:"<<bt.biTreeDepth(root)<<endl;
	cout<<"叶子个数:"<<bt.leafCount(root)<<endl;
	cout<<"节点个数:"<<bt.nodeCount(root)<<endl;
	
	cout<<"删除节点为d的子树"<<endl;
	bt.deleteSibTree(root, "d");
	cout<<"------前序遍历------ "<<endl;
	bt.preOrder(root);
	cout<<endl;
	cout<<"------中序遍历------ "<<endl;
	bt.inOrder(root);
	cout<<endl;
	return 0;
}

 4.总结

每个操作的一些注意事项都在代码中进行了说明,主要注意一下,建立二叉树的时候,如何输入节点?见下图:


 

  • 大小: 12.9 KB
分享到:
评论
2 楼 hao3100590 2012-10-03  
wentfar 写道
void creatTree(Node<T>* root);
这个函数是有问题的。
二叉树本质上是用地址(Node<T>* root)来表示的。
根据形参的值传递规则,要改变原二叉树,必须传递地址的地址,即为(Node<T>** root)。

好的,谢谢,这个函数的确有问题,参数使用指针引用或者双指针即可
1 楼 wentfar 2012-09-29  
void creatTree(Node<T>* root);
这个函数是有问题的。
二叉树本质上是用地址(Node<T>* root)来表示的。
根据形参的值传递规则,要改变原二叉树,必须传递地址的地址,即为(Node<T>** root)。

相关推荐

Global site tag (gtag.js) - Google Analytics