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