数据结构(树和二叉树)

1. 前序打印叶子结点

【问题描述】设计算法,要求按照前序遍历方式打印二叉树的叶子结点。

【输入形式】一行字符串,该行是扩展二叉树的前序遍历序列,用于构造二叉树。

【输出形式】二叉树的前序叶子遍历序列(中间用空格隔开)。

【样例输入】AB#D##C##

【样例输出】

D C
#include <iostream>
#include <string>
using namespace std;
struct BiNode {
	char data;
	BiNode *L_child;
	BiNode *R_child;
};

class BiTree {
	public:
		BiTree() {
			root=Creat();
		}
		~BiTree() {
			Release(root);
		}
		void PreOrder() {
			PreOrder(root);
		}

	private:
		BiNode *Creat();
		void Release(BiNode *bt);
		void PreOrder(BiNode *bt);
		BiNode *root;
};

BiNode *BiTree::Creat() {
	BiNode *bt;
	char a=getchar();
	if(a=='#')bt= NULL;
	else {
		bt=new BiNode;
		bt->data=a;
		bt->L_child=Creat();
		bt->R_child=Creat();
	}
	return bt;
}

void BiTree::Release(BiNode *bt) {
	if(bt==NULL)return;
	else {
		Release(bt->L_child);
		Release(bt->R_child);
		delete bt;
	}
}

void BiTree::PreOrder(BiNode *bt) {
	if(bt==NULL)return;
	else {
		if(bt->L_child==NULL&&bt->R_child==NULL)
			cout<<bt->data<<" ";
		PreOrder(bt->L_child);
		PreOrder(bt->R_child);
	}
}

int main() {
	BiTree T;
	T.PreOrder();
	return 0;
}

2. 求二叉树的结点个数

【问题描述】设计算法求二叉树的结点个数。

【输入形式】一行字符串,该行是扩展二叉树的前序遍历序列,用于构造二叉树。

【输出形式】二叉树中的结点个数。

【样例输入】AB#D##C##

【样例输出】

4
#include <iostream>
using namespace std;
struct BiNode {
	char data;
	BiNode *L_child;
	BiNode *R_child;
};
class BiTree {
	public:
		BiTree() {
			root=Creat();
		}
		~BiTree() {
			Release(root);
		}
		int CountNode() {
			return CountNode(root);
		}

	private:
		BiNode *Creat();
		void Release(BiNode *bt);
		int CountNode(BiNode *bt);
		BiNode *root;
};
int BiTree::CountNode(BiNode *bt) {
	int count=0;
	if(bt==NULL)return count;
	else {
		if(bt->data!='#') {
			count++;
			count+=CountNode(bt->L_child);
			count+=CountNode(bt->R_child);
		}
	}
	return count;
}
BiNode* BiTree::Creat() {
	BiNode *bt;
	char a=getchar();
	if(a=='#')bt=NULL;
	else {
		bt=new BiNode;
		bt->data=a;
		bt->L_child=Creat();
		bt->R_child=Creat();
	}
	return bt;
}
void BiTree::Release(BiNode *bt) {
	if(bt==NULL)return;
	else {
		Release(bt->L_child);
		Release(bt->R_child);
		delete bt;
	}
}
int main() {
	BiTree T;
	cout<<T.CountNode();
	return 0;
}

3. 求二叉树的深度

【问题描述】设计算法求二叉树的深度。

【输入形式】一行字符串,该行是扩展二叉树的前序遍历序列,用于构造二叉树。

【输出形式】二叉树的深度。

【样例输入】AB#D##C##

【样例输出】

3
#include <iostream>

using namespace std;
struct BiNode {
	char data;
	BiNode *L_child;
	BiNode *R_child;
};

class BiTree {
	public:
		BiTree() {
			root = Creat();
		}

		~BiTree() {
			Release(root);
		}

		int CountDepth() {
			return CountDepth(root);
		}

	private:
		BiNode *Creat();

		void Release(BiNode *bt);

		int CountDepth(BiNode *bt);

		BiNode *root;
};
BiNode* BiTree::Creat() {
	BiNode *bt;
	char a=getchar();
	if(a=='#')bt=NULL;
	else {
		bt=new BiNode;
		bt->data=a;
		bt->L_child=Creat();
		bt->R_child=Creat();
	}
	return bt;
}
void BiTree::Release(BiNode *bt) {
	if(bt==NULL)return;
	else {
		Release(bt->L_child);
		Release(bt->R_child);
		delete bt;
	}
}
int BiTree::CountDepth(BiNode *bt) {
	int i=0,j=0;
	if(bt==NULL)return 0;
	else {
		i=CountDepth(bt->L_child);
		j=CountDepth(bt->R_child);
	}
	return i>=j?i+1:j+1;
}
int main() {
	BiTree T;
	cout<<T.CountDepth();
	return 0;
}

4. 二叉链表存储结构下,求结点x的双亲结点

【问题描述】以二叉链表为存储结构,编写算法求二叉树中结点x的双亲。

【输入形式】两行,第一行是扩展二叉树的前序遍历序列,第二行是待查询结点x

【输出形式】如果结点x存在双亲,则输出其双亲的数值;否则输出“NO”。

【样例输入】AB#D##C##

D

【样例输出】

B
#include <iostream>

using namespace std;
struct BiNode {
	char data;
	BiNode *L_child;
	BiNode *R_child;
};

class BiTree {
	public:
		BiTree() {
			root = Creat();
		}

		~BiTree() {
			Release(root);
		}

		void Parent(char x) {
			Parent(root,x);
		};

	private:
		BiNode *root;

		BiNode *Creat();

		void Release(BiNode *bt);
		void Parent(BiNode *bt,char x);
};

BiNode *BiTree::Creat() {
	BiNode *bt;
	char a = getchar();
	if (a == '#')bt = NULL;
	else {
		bt = new BiNode;
		bt->data = a;
		bt->L_child = Creat();
		bt->R_child = Creat();
	}
	return bt;
}

void BiTree::Release(BiNode *bt) {
	if (bt == NULL)return;
	else {
		Release(bt->L_child);
		Release(bt->R_child);
		delete bt;
	}
}

void BiTree::Parent(BiNode *bt, char x) {
	if (bt->L_child==NULL&&bt->R_child==NULL)return;
	if(bt->L_child!=NULL) {
		if (bt->L_child->data == x)
			cout << bt->data;
		else {
			Parent(bt->L_child, x);
		}
	}
	if(bt->R_child!=NULL) {
		if (bt->R_child->data == x)
			cout<<bt->data;
		else {
			Parent(bt->R_child,x);
		}
	}
}
int main() {
	BiTree T;
	getchar();
	char a=getchar();
	T.Parent(a);

}

5. 删除以值x为根结点的子树

【问题描述】以二叉链表为存储结构,在二叉树中删除以值x为根结点的子树。

【输入形式】两行,第一行是扩展二叉树的前序遍历序列,第二行是待查询结点x。

【输出形式】如果结点x存在,则删除以值x为根结点的子树;否则无操作。最后输出操作后二叉树的中序遍历序列(中间用空格隔开)。如果是空二叉树,则输出“Empty”。

【样例输入】AB#D##C##

D

【样例输出】

B A C
#include <iostream>

using namespace std;
struct BiNode {
	char data;
	BiNode *L_child;
	BiNode *R_child;
};

class BiTree {
	public:
		BiNode* getRoot() {
			return root;
		}
		BiTree() {
			root = Create();
		}

		~BiTree() {
			Release(root);
		}

		void Release(BiNode *bt);

		void DeleteChildTree(char x) {
			DeleteChildTree(root, x);
		}

		void InOrder() {
			InOrder(root);
		}

	private:
		BiNode *root;

		BiNode *Create();

		void DeleteChildTree(BiNode *bt, char x);

		void InOrder(BiNode *bt);
};

BiNode *BiTree::Create() {
	BiNode *bt;
	char a = getchar();
	if (a == '#')bt = NULL;
	else {
		bt = new BiNode;
		bt->data = a;
		bt->L_child = Create();
		bt->R_child = Create();
	}
	return bt;
}

void BiTree::Release(BiNode *bt) {
	if (bt == NULL)return;
	else {
		Release(bt->L_child);
		Release(bt->R_child);
		delete bt;
	}
}

void BiTree::DeleteChildTree(BiNode *bt, char x) {
	if (bt == NULL)return;
	else {
		if (bt->L_child != NULL && bt->L_child->data == x) {
			bt->L_child = NULL;
		}
		if (bt->R_child != NULL && bt->R_child->data == x) {
			bt->R_child = NULL;
		}
		DeleteChildTree(bt->L_child, x);
		DeleteChildTree(bt->R_child, x);
	}
}

void BiTree::InOrder(BiNode *bt) {
	if (bt == NULL) {
		return;
	} else {
		InOrder(bt->L_child);
		cout << bt->data << " ";
		InOrder(bt->R_child);
	}
}

int main() {
	BiTree T;
	getchar();
	char a = getchar();
	if(T.getRoot()->data==a) {
		cout<<"Empty"<<endl;
		return 0;
	}
	T.DeleteChildTree(a);
	T.InOrder();
	return 0;
}


6. 基于顺序存储结构的前序遍历

【问题描述】一个具有n个结点的二叉树采用顺序存储结构,编写算法对该二叉树进行前序遍历。

【输入形式】一行,该二叉树按照对应完全二叉树的层序遍历序列(即某个结点没有左孩子或者右孩子时,添加特殊标记#)。

【输出形式】二叉树的前序遍历序列;如果是空二叉树,则输出“Empty”。

【样例输入】ABC#D

【样例输出】

A B D C
#include<iostream>
#include<string.h>
#include<cstdlib>
using namespace std;
char array[1000];
void preOrder(int i) {
	if(array[i]=='#')
		return;
	else {
		cout<<array[i]<<" ";
		preOrder(i*2);
		preOrder(i*2+1);
	}
}
int main() {
	string s;
	memset(array,'#',sizeof(array));
	cin>>s;
	for(int i=0; i<s.length(); i++) {
		if(s[i]!='#') {
			array[i+1]=s[i];
		}
	}
	preOrder(1);
	return 0;
}

7. 扩展序列构造二叉树

【问题描述】

给出某扩展二叉树的前序遍历序列(虚结点的值用“#”表示),构造二叉树,并输出该二叉树的中序遍历序列。

【输入形式】扩展二叉树的前序遍历序列

【输出形式】二叉树的中序遍历序列

【样例输入】AB#D##C##

【样例输出】BDAC

#include<stack>
#include<cstdlib>
#include<iostream>
using  namespace  std;
template<class  DataType>
struct  BiNode {
	DataType  data;
	BiNode<DataType>  *lchild,*rchild;
};
template<class  DataType>
class  BiTree {
	public:
		BiTree() {
			root  =  PreCreate(root);
		};
		~BiTree() {
			Release(root);
		};
		void  InOrder() {
			InOrder(root);
		};
	private:
		BiNode<DataType>  *root;
		BiNode<DataType>*  PreCreate(BiNode<DataType>*  bt);
		void  Release(BiNode<DataType>  *  bt);    //后序释放
		void  InOrder(  BiNode<DataType>*  bt);
};

template<class  DataType>
BiNode<DataType>*  BiTree<DataType>::PreCreate(BiNode<DataType>*  bt) {
	char t;
	t=getchar();
	if(t=='#')
		bt=NULL ;
	else {
		bt=new BiNode<DataType>;
		bt->data=t;
		bt->lchild=PreCreate(bt->lchild);
		bt->rchild=PreCreate(bt->rchild);
	}
	return bt;

}
template<class  DataType>
void  BiTree<DataType>::Release(BiNode<DataType>  *bt) {
	if(bt  ==  NULL)  return  ;
	else {
		Release(bt->lchild);
		Release(bt->rchild);
		bt  =  NULL;
		delete  bt;
	}
}
template<class  DataType>
void  BiTree<DataType>::InOrder(BiNode<DataType>*  bt) {
	if(bt==NULL)
		return ;
	else {
		InOrder(bt->lchild);
		cout<<bt->data;
		InOrder(bt->rchild);
	}
}

int  main() {
	BiTree<char>  biTree;
	biTree.InOrder();
	biTree.~BiTree();
	return  0;
}

8. 二叉树层序遍历序列

【问题描述】给出某扩展二叉树的前序遍历序列(虚结点的值用“#”表示),构造二叉树,并输出该二叉树的层序遍历序列。

【输入形式】扩展二叉树的前序遍历序列

【输出形式】二叉树的层序遍历序列

【样例输入】AB#D##C##

#include<queue>
#include<cstdlib>
#include<iostream>
using  namespace  std;
template<class  DataType>
struct  BiNode {
	DataType  data;
	BiNode<DataType>  *lchild,*rchild;
};
template<class  DataType>
class  BiTree {
	public:
		BiTree() {
			root  =  PreCreate(root);
		};
		~BiTree() {
			Release(root);
		};
		void  LeverOrder(  );
	private:
		BiNode<DataType>  *root;
		BiNode<DataType>*  PreCreate(BiNode<DataType>*  bt);
		void  Release(BiNode<DataType>  *  bt);    //后序释放
};


template<class  DataType>
BiNode<DataType>*  BiTree<DataType>::PreCreate(BiNode<DataType>*  bt) {
	char t;
	t=getchar();
	if(t=='#')
		bt=NULL;
	else {
		bt=new BiNode<DataType>;
		bt->data=t;
		bt->lchild=PreCreate(bt->lchild);
		bt->rchild=PreCreate(bt->rchild);
	}
	return bt;
}
template<class  DataType>
void  BiTree<DataType>::Release(BiNode<DataType>  *bt) {
	if(bt  ==  NULL)  return  ;
	else {
		Release(bt->lchild);
		Release(bt->rchild);
		bt  =  NULL;
		delete  bt;
	}
}
template<class  DataType>
void  BiTree<DataType>::LeverOrder() {
	queue<BiNode<DataType> > Q;
	if(root==NULL)return;
	Q.push(*root);
	while(!Q.empty()) {
		BiNode<DataType> q;
		q=Q.front();
		Q.pop();
		cout<<q.data;
		if(q.lchild) {
			Q.push(*q.lchild);
		}
		if(q.rchild) {
			Q.push(*q.rchild);
		}
	}
}

int  main() {
	BiTree<char>  biTree;
	biTree.LeverOrder();
	biTree.~BiTree();
	return  0;
}

9. 孩子链表表示法——找孩子

【问题描述】如果某树采用这种孩子链表表示法存储,现如今需要查询某个结点的某个孩子,如果该孩子存在,则输出孩子信息;否则输出NO。比如下面这棵树,查询结点B的第3个孩子,该孩子存在且是结点F;若要查询结点B的第4个孩子,该孩子不存在,则输出NO。

【输入形式】第一行树种结点的个数n;第二行各结点的信息;第三行双亲孩子关系的个数row;接下row行分别输入双亲孩子关系,第一个表示双亲结点,第二个表示孩子结点;最后一行表示待查询结点elem的第i个孩子。

【输出形式】如果待查询结点elem的第i个孩子存在,则输出孩子信息;否则输出NO。

【样例输入】
9

A B C D E F G H I

8

A B

A C

B D

B E

B F

C G

C H

E I

B 3

【样例输出】F

#include<cstdlib>
#include<iostream>
using  namespace  std;
struct  CTNode {
	int  child;//元素在数组中的下标
	CTNode  *next;
};
template<class  DataType>
struct  CBNode {
	DataType  data;
	CTNode  *firstChild;
};
template<class  DataType>
class  ChildLink {
	public:
		ChildLink(int  num);
		~ChildLink();
		bool  findChild(DataType  elem,int  i,DataType  &value);
		int  findPos(DataType  elem);
	private:
		CBNode<DataType>*  arrayPtr;
		int  nodeNUm;
};


template<class  DataType>
ChildLink<DataType>::ChildLink(int  num) {
	arrayPtr  =  new  CBNode<DataType>[num+1];
	CTNode**arrayRear  =  new  CTNode*[num+1];//尾插
	nodeNUm  =  num;
	for(int  i  =  1; i<=  num; i++) {
		DataType  temp;
		cin>>temp;
		arrayPtr[i].data  =  temp;
		arrayPtr[i].firstChild  =  NULL;
	}
	int  row;
	cin>>row;
	for(int  i  =  0; i  <  row; i++) {
		DataType  parent,child;
		cin>>parent>>child;
		int  parLoc  =  findPos(parent);
		int  chiLoc  =  findPos(child);
		if(arrayPtr[parLoc].firstChild  ==  NULL) { //第一个孩子
			arrayPtr[parLoc].firstChild  =  new  CTNode;
			arrayPtr[parLoc].firstChild  ->child  =  chiLoc;
			arrayPtr[parLoc].firstChild  ->next  =  NULL;
			arrayRear[parLoc]  =  arrayPtr[parLoc].firstChild  ;
		} else {
			CTNode*  s=  new  CTNode;//尾插
			s->child  =  chiLoc;
			s->next  =  NULL;
			arrayRear[parLoc]->next  =  s;
			arrayRear[parLoc]  =  s;
		}
	}
}

template<class  DataType>
ChildLink<DataType>::~ChildLink() {
	CTNode*  first  =  NULL;
	for(int  i=1; i<=nodeNUm; i++) {
		first  =  arrayPtr[i].firstChild;
		while(first  !=  NULL) {
			arrayPtr[i].firstChild  =  first->next;
			delete  first;
			first  =  arrayPtr[i].firstChild;
		}
	}
}
//查找元素elem的第i个孩子
template<class  DataType>
bool  ChildLink<DataType>::findChild(DataType  elem,int  i,DataType  &value) {
	int preLoc=findPos(elem); //找到elem在数组中的位置
	CTNode* first = arrayPtr[preLoc].firstChild; //获得第一个孩子地址
	int count=1;
	while(first&&count<i) {
		first=first->next;
		count++;
	}
	if(first) { //表示存在第i个孩子
		value=arrayPtr[first->child].data; //引用变量赋值
		return true;
	} else
		return false;

}
template<class  DataType>
int  ChildLink<DataType>::findPos(DataType  elem) {
	for(int  i  =  1; i  <=  nodeNUm; i++)
		if(arrayPtr[i].data  ==  elem)  return  i;
	return  0;//查找失败
}


int  main() {
	int  n;
	cin>>n;
	ChildLink<char>  childLink(n);
	char  value,elem;
	int  i;
	cin>>elem;
	cin>>i;
	if(childLink.findChild(elem,i,value))
		cout<<value<<endl;
	else
		cout<<"NO"<<endl;
	childLink.~ChildLink();
	return  0;
}


10. 哈夫曼树以及哈夫曼编码

【问题描述】给出n个字符,以及这些字符使用的频率,设计最经济的编码方案,并输出任意一个字符的哈弗曼编码。如果该字符不存在,则输出“NO”,否则输出对应的哈夫曼编码

【输入形式】第一行字符个数n;第二行n个字符的使用频率(中间用逗号分隔开);第三行需要输出哈夫曼编码的字符序号。

【输出形式】某字符的哈夫曼编码

【样例输入】

4

2 3 4 5

2

【样例输出】01

#include<iostream>
#include<string.h>
using  namespace  std;
struct  HTNode {
	int  weight;
	int  parent,lchild,rchild;
};
class  HuffmanTree {
	public:
		HuffmanTree(int  W[],int  n);
		~HuffmanTree();
		void  Select(HTNode*  HT,int  len,int  &i1,int  &i2);
		void  CreatHuffmanCode(  );
		void  showHuffmanCode(int  i);
	private:
		int  nodeNum;
		HTNode*  HT;//存储哈夫曼树
		char**  HTC;//存储哈夫曼编码
};

HuffmanTree::HuffmanTree(int  W[],int  n) {
	nodeNum  =  n; //节点数目
	HT  =  new  HTNode[2*n  -1]; //存储节点的哈夫曼树
	//初始化
	for(int  i=0; i  <  2*nodeNum  -1; i++) {
		HT[i].lchild  =  -1;
		HT[i].rchild  =  -1;
		HT[i].parent  =-1;
	}
	for(int  i=0; i  <  nodeNum; i++)
		HT[i].weight  =  W[i];
	//哈弗曼树构造
	for(int  k  =  nodeNum; k  <  2*nodeNum-1; k++) {
		int  i1,i2;
		Select(HT,k,i1,i2);
		HT[k].weight  =  HT[i1].weight  +  HT[i2].weight;
		HT[i1].parent  =  k;
		HT[i2].parent  =  k;
		HT[k].lchild  =  i1;
		HT[k].rchild  =  i2;
	}
}
HuffmanTree::~HuffmanTree() {
	HT  =  NULL;
	delete  HT;
	HTC  =  NULL;
	delete  []HTC;
}
void  HuffmanTree::Select(HTNode*  HT,int  len,int  &i1,int  &i2) {
	int first_min,second_min;
	first_min=100000;
	second_min=10000;
	i1=-1;//节点中最小权值的下标
	i2=-1;//节点中倒数第二权值小的下标
	for(int i=0; i<len; i++) {
		if(HT[i].parent!=-1)continue;//该节点已经使用过
		if(HT[i].weight<first_min) {
			second_min=first_min;
			i2=i1;
			first_min=HT[i].weight;
			i1=i;
		} else if(HT[i].weight<second_min) {
			second_min=HT[i].weight;
			i2=i;
		}
	}
}
//进行赫夫曼编码                                                                                                //  CreatHuffmanTree
void  HuffmanTree::CreatHuffmanCode(  ) {
	//从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中
	int  i,start,c,f;
	HTC=new  char*[nodeNum];                                                                  //分配n个字符编码的头指针矢量
	char  *cd=new  char[nodeNum];                                                        //分配临时存放编码的动态数组空间
	cd[nodeNum-1]='\0';                                                                        //编码结束符
	for(i=0; i<nodeNum; ++i) {
		//逐个字符求赫夫曼编码
		start=nodeNum-1;                                                                    //start开始时指向最后,即编码结束符位置
		c=i;
		f=HT[i].parent;                                                          //f指向结点c的双亲结点
		while(f!=-1) {
			//从叶子结点开始向上回溯,直到根结点
			--start;                                                                    //回溯一次start向前指一个位置
			if(HT[f].lchild==c)
				cd[start]='0';                                                //结点c是f的左孩子,则生成代码0
			else
				cd[start]='1';                                                  //结点c是f的右孩子,则生成代码1
			c=f;
			f=HT[f].parent;                                                  //继续向上回溯
		}                                                                                            //求出第i个字符的编码
		HTC[i]=new  char[nodeNum-start];                                          //  为第i  个字符编码分配空间
		strcpy(HTC[i],  &cd[start]);                                        //将求得的编码从临时空间cd复制到HC的当前行中
	}
	delete  cd;                                                                                //释放临时空间
}
void  HuffmanTree::showHuffmanCode(int  i) {
	cout<<HTC[i-1]<<endl;
}
int  main() {
	int  n;
	cin>>n;
	int  W[n];
	for(int  i=0; i<n; i++)
		cin>>W[i];
	HuffmanTree  huffmanTree(W,n);
	huffmanTree.CreatHuffmanCode();
	int  i;
	cin>>i;
	if(i<1  ||  i>  n)
		cout<<"NO"<<endl;
	else
		huffmanTree.showHuffmanCode(i);
	huffmanTree.~HuffmanTree();
	return  0;
}

结语

如果你发现文章有什么问题,欢迎留言指正。
如果你觉得这篇文章还可以,别忘记点个赞加个关注再走哦。
如果你不嫌弃,还可以关注微信公众号———梦码城(持续更新中)。
梦码在这里感激不尽!!

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦码城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值