1. 求节点的哈夫曼的带权路径长度
【问题描述】
已知输入一串正整数,正整数之间用空格键分开,请建立一个哈夫曼树,以输入的数字为叶节点,求这棵哈夫曼树的带权路径长度。
【输入形式】
首先输入正整数的个数,然后接下来为接下来的正整数,正整数个数不超过10个
【输出形式】
输出相应的权值
【样例输入】
5 4 5 6 7 8
【样例输出】
69
【样例说明】
【评分标准】
参考代码:
#include<iostream>
using namespace std;
typedef struct HTNode {
unsigned int weight;
unsigned int parent, lchild, rchild;
}HTNode, * HuffmanTree;//动态分配数组存储哈夫曼树
void Select(HuffmanTree HT, int n, int& s1, int& s2)
{ //从这m个数里边选择最小的2个//把第一个进行标记就ok
int i;//从下标为1的位置开始计数
//int min=HT[1].weight;这里直接赋值不合理,假如第一次那个1就是最小被选中,那么第2次还是被选中
int min1 = 1000000;
int min2 = 1000000;//规定一个特别大的数
for (i = 1; i <= n; i++)
{
if (HT[i].parent == 0 && min1 > HT[i].weight)
{
min1 = HT[i].weight;
s1 = i;
}
}
for (i = 1; i <= n; i++)
{
if (i != s1 && HT[i].parent == 0)//注意这个i!=s1标记min,即s1 s2不能是同一个结点,还保证了s1的权重<=s2的权重
if (HT[i].weight < min2)
{
min2 = HT[i].weight;
s2 = i;
}
}
}
int WPLHuffmanTree(HuffmanTree& HT, unsigned int* w, int n) {
int sum = 0;
if (n <= 1)
return 0;
int m = 2 * n - 1;
int i;
HuffmanTree p;
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
for (p = HT+1, i = 1; i <= n; ++i, ++p, ++w)//0号单元没用
*p = { *w,0,0,0 };//等价于p->weight = *w;p->parent = 0;p->lchild = 0;p->rchild = 0;
for (; i <= m; ++i, ++p)//m-n个非叶子结点(从n+1到m),给权重赋值为空
*p = { 0,0,0,0 };//等价于p->weight = 0;p->parent = 0;p->lchild = 0;p->rchild = 0;
for (i = n + 1; i <= m; ++i) {
//在HT[1...i-1]选择parent为0且weight最小的两个结点,其序号分别为s1和s2
int s1, s2;
Select(HT, i - 1, s1, s2);
HT[s1].parent = i; HT[s2].parent = i;
HT[i].lchild = s1; HT[i].rchild = s2;//左边小右边大
HT[i].weight = HT[s1].weight + HT[s2].weight;
sum += HT[i].weight;
}
return sum;
}
int main() {
int n;
cin >> n;
char c = getchar();
unsigned int* w = new unsigned int[n];
for (int i = 0; i < n; i++) {
cin >> w[i];
}
HuffmanTree t;
cout<<WPLHuffmanTree(t, w, n);
}
2. 二叉排序树的构建及其遍历
【问题描述】
对一组输入数据构建相应的二叉排序树,并利用其中序遍历对数据进行升序排序。(此题人工批改,必须使用二叉树进行排序,其它算法不得分)
【输入形式】
数据个数,数据。(以空格分割)
【输出形式】
排序之后的数据。(以空格分割)
【样例输入】
5 22 -15 4 89 30
【样例输出】
-15 4 22 30 89
【样例说明】
【评分标准】(此题人工批改,必须使用二叉树进行排序,其它算法不得分)
参考代码:
#include<iostream>
using namespace std;
//数值型
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
//字符串型
#define SEQ(a,b) (!strcmp((a),(b)))
#define SLT(a,b) (strcmp((a),(b))<0)
#define SLQ(a,b) (strcmp((a),(b))<=0)
typedef int TElemType;
typedef struct BiTNode {
TElemType data;
struct BiTNode* lchild,* rchild;
}BiTNode,*BiTree;
void CreatBiTree(BiTree& T)
{
T = (BiTNode*)malloc(sizeof(BiTNode));
if (T == NULL) exit(-1);
T->rchild = NULL;
T->lchild = NULL;
}
void InsertBST(BiTree& T,TElemType e)
{
if (!T) {
CreatBiTree(T);
T->data = e;
}
else if LT(e, T->data)
InsertBST(T->lchild,e);//小于往左走
else
InsertBST(T->rchild, e);//大于往右走
}
void PrintElement(TElemType e)
{
cout<<e<<" ";
}
void InOrder(BiTree T, void(*Visit)(TElemType)) {//中序遍历
if (T) {
InOrder(T->lchild, Visit);
Visit(T->data);
InOrder(T->rchild, Visit);
}
}
int main() {
int n;
cin >> n;
BiTree t=NULL;
TElemType e;
for (int i = 0; i < n; i++) {
cin >> e;
InsertBST(t, e);
}
InOrder(t, PrintElement);
}
3. 从下至上按层遍历二叉树
【问题描述】
给定一颗二叉树,要求从下至上按层遍历二叉树,每层的访问顺序是从左到右,每一层单独输出一行。
【输入形式】
广义表表示的二叉树,结点元素类型为整型,且都大于0,例如:1( 2( 3 ( 4, 5 ) ), 6( 7, 8( 9, 10 ) ) )
【输出形式】
从下至上,打印每一层的结点元素值,元素间以空格隔开。每层的访问顺序是从左到右,每一层单独输出一行。
【样例输入】
1(2(3(4,5)),6(7,8(9,10))),字符串内没有空格
【样例输出】
4 5 9 10
3 7 8
2 6
1
【样例说明】
【评分标准】
本题目主要考察两个知识点:
1.创建二叉树存储结构
2.按层次遍历二叉树的算法
参考代码:
#include<iostream>
using namespace std;
#define MAXSIZE 100
#define RESIZE 10
typedef struct BiTNode
{
int data;
int depth;
struct BiTNode* lchild,*rchild;
}BiTNode, * BiTree;
typedef BiTree SElemType;
typedef struct {
SElemType* base;
SElemType* top;
int size;
}Stack;
void InitStack(Stack& s) {
s.base = (SElemType*)malloc(MAXSIZE * sizeof(SElemType));
if (!s.base)
exit(-2);
s.top = s.base;
s.size = MAXSIZE;
}
void Push(Stack& s, SElemType e) {
if (s.top - s.base >= s.size) {
s.base = (SElemType*)realloc(s.base, (MAXSIZE + RESIZE) * sizeof(SElemType));
if (!s.base)
exit(-2);
s.top = s.base + s.size;
s.size += MAXSIZE;
}
*s.top++ = e;
}
void Pop(Stack& s, SElemType& e) {
if (s.top == s.base)
return;
e = *--s.top;
}
SElemType gettop(Stack s, SElemType& e) {
if (s.top != s.base)
e = *(s.top - 1);
return e;
}
//用栈建立二叉树
void InitBiTree(BiTree* T)
{
Stack s;
InitStack(s);
char a[2*MAXSIZE];
cin >> a;
int n= 0;
int t = 0;
int e[MAXSIZE];
int flag = 0;
int i = 0;
//由于可能是多位数,所以将字符全部代换成整数形式
while (a[i] != '\0')
{
flag = 0;
if (a[i] == ',')
{
t = 0;
e[n] = -1;
}
else if (a[i] == '(')
{
t = 0;
e[n] = -2;
}
else if (a[i] == ')')
{
t= 0;
e[n] = -3;
}
else if ((a[i] >= '0') && (a[i] <= '9'))
{
while ((a[i] >= '0') && (a[i] <= '9'))//注意多位数
{
t = t * 10 + (a[i] - '0');
flag = 1;
i = i + 1;
}
e[n] = t;
}
n = n + 1;
if (flag == 0)//如果flag为1,则不需要读下一个字符
{
i++;
}
}
int flag1 = 0;//flag1为1代表左子树,为2代表右子树
BiTree Bt = NULL;
SElemType el;
for (int j = 0; j < n; j++)
{
switch (e[j])
{
case -1:
flag1 = 2;
Bt = NULL;
break;
case -2://左子树压栈
s.top++;
flag1 = 1;
Bt = NULL;
break;
case -3://')'出栈
Pop(s,el);
Bt = NULL;
break;
default://如果都不是,则创建现结点
Bt = (BiTree)malloc(sizeof(BiTNode));
Bt->data = e[j];
Bt->lchild = NULL;
Bt->rchild = NULL;
}
if (flag1 == 1 && Bt)
{
(*(s.top - 1))->lchild = Bt;
*s.top= Bt;
if (e[j] > 0)//为数字时,深度加1,便于后续从下至上输出
{
Bt->depth = (*(s.top - 1))->depth + 1;
}
}
else if (flag1 == 2 && Bt)
{
(*(s.top - 1))->rchild = Bt;
*s.top = Bt;
if (e[j] > 0)
{
Bt->depth = (*(s.top - 1))->depth + 1;
}
}
else if (flag1 == 0)//为根结点时,注意将第一个创建的结点赋给树根结点
{
*T = Bt;
*s.top = Bt;
Bt->depth = 1;//根节点深度为1
}
}
}
typedef BiTree QElemType;
typedef struct SQueue {
QElemType* base;
int front;
int rear;
}SQueue;
void InitQueue(SQueue& q) {
q.base = (QElemType*)malloc(MAXSIZE * sizeof(QElemType));
if (!q.base)
exit(-2);
q.front = q.rear = 0;
}
void EnQueue(SQueue& q, QElemType e) {//循环队列入队
if ((q.rear + 1) % MAXSIZE == q.front)//队满
return;
q.base[q.rear] = e;
q.rear = (q.rear + 1) % MAXSIZE;
}
int QueueLength(SQueue& q) {
return (q.rear - q.front + MAXSIZE) % MAXSIZE;
}
void DeQueue(SQueue& q, QElemType& e) {
if (q.front == q.rear)//队空
return;
e = q.base[q.front];
q.front = (q.front + 1) % MAXSIZE;
}
bool IsEmpty(SQueue& q) {
if (q.front == q.rear)
return true;
else
return false;
}
int temp[MAXSIZE][2];//设置二维数组,分别记录结点值和深度
//按层遍历
int LevelOrder(QElemType T)
{
SQueue q;
InitQueue(q);
BiTree p = (BiTNode*)malloc(sizeof(BiTNode));
int i = 0;
if (T)
{
EnQueue(q, T);
}
while (!IsEmpty(q))//如果非空
{
DeQueue(q, p);//出队
temp[i][0] = p->data;//0为结点值
temp[i][1] = p->depth;//1为深度
i = i + 1;
if (p->rchild)//由于要从下至上输出,所以按层遍历时从右至左遍历
{
EnQueue(q, p->rchild);
}
if (p->lchild)
{
EnQueue(q, p->lchild);
}
}
return i - 1;//返回结点个数下标最大值
}
int main()
{
BiTree T;
InitBiTree(&T);
int level = LevelOrder(T);
int d = temp[level][1];//最后一个结点的深度为树的深度
for (; level >= 0; level--)
{
if (d != temp[level][1])//如果深度不同,证明应输出上一个深度的结点了
{
cout << endl;
d = d - 1;
}
cout<<temp[level][0]<<" ";
}
return 0;
}
4. 已知一个二叉树的中序遍历序列和后序遍历序列,求这棵树的前序遍历序列
【问题描述】
已知一个二叉树的中序遍历序列和后序遍历序列,求这棵树的前序遍历序列。
【输入形式】
一个树的中序遍历序列 该树后序遍历序列,中间用空格分开。输入序列中仅含有小写字母,且没有重复的字母
【输出形式】
一个树的前序遍历序列
【样例输入】
dbeafcg debfgca
【样例输出】
abdecfg
参考代码:
#include<iostream>
#include<cstdio>
using namespace std;
typedef char TElemType;
typedef struct BiTNode {
TElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
int Search(string a, char b, int l) {
for (int i = 0; i < l; i++)
if (a[i] == b)
return i;
}
int length(string s) {
int sum = 0;
for (int i = 0; s[i] != '\0'; i++)
sum++;
return sum;
}
void PrintElement(TElemType e)
{
cout << e;
}
void PreOrder(BiTree T, void(*Visit)(TElemType)) {//先序遍历
if (T) {
Visit(T->data);
PreOrder(T->lchild, Visit);
PreOrder(T->rchild, Visit);
}
}
BiTree Inittree(string s1,string s2)//s1后序遍历序列,s2中序遍历序列
{
BiTree t = NULL;
int l=length(s1);
if (l > 0)
{
t = (BiTree)malloc(sizeof(BiTNode));
t->data = s1[l - 1];//根节点是后序遍历的最后一个
t->lchild = NULL;
t->rchild = NULL;
string s3, s4,s5,s6;
int i= Search(s2, s1[l - 1], l);//找到根结点在中序遍历中的位置
s3 = s2.substr(0, i);//在中序序列取出左子树
s4 = s2.substr(i + 1, length(s2)- i - 1);//在中序序列取出右子树
s5 = s1.substr(0, i);// 在后序序列取出左子树
s6 = s1.substr(i, length(s1) - i - 1);// 在后序序列取出右子树
t->lchild = Inittree(s5, s3);
t->rchild = Inittree(s6, s4);
}
return t;
}
int main() {
string s, s0;
cin >> s0;
char c = getchar();//存储空格
cin >> s;
BiTree t = Inittree(s, s0);
PreOrder(t, PrintElement);
}
5. 二叉查找树的后序遍历
【问题描述】输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
【输入形式】输入任意长度的数组,数字之间空格分开
【输出形式】true 或者 false
【样例输入】输入5 7 6 9 11 10 8
【样例输出】true
【样例说明】由于这一整数序列是如下树的后序遍历结果:
8
/ \
6 10
/ \ / \
5 7 9 11
因此返回true。
【评分标准】暴力求解法不得分。
参考代码:
#include<iostream>
using namespace std;
//数值型
#define EQ(a,b) ((a)==(b))
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)<=(b))
//字符串型
#define SEQ(a,b) (!strcmp((a),(b)))
#define SLT(a,b) (strcmp((a),(b))<0)
#define SLQ(a,b) (strcmp((a),(b))<=0)
typedef int TElemType;
typedef struct BiTNode {
TElemType data;
struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;
static int i = 0;
TElemType b[100];
void CreatBiTree(BiTree& T)
{
T = (BiTNode*)malloc(sizeof(BiTNode));
if (T == NULL) exit(-1);
T->rchild = NULL;
T->lchild = NULL;
}
void InsertBST(BiTree& T, TElemType e)
{
if (!T) {
CreatBiTree(T);
T->data = e;
}
else if LT(e, T->data)
InsertBST(T->lchild, e);//小于往左走
else
InsertBST(T->rchild, e);//大于往右走
}
void reserve(TElemType a[],int n) {//二叉排序树后序遍历递归放到数组后是逆序的(单叉是正确的),所以需要逆转数组
int i = 0, j = n - 1;
int t;
for (; i < n / 2; i++, j--)
{
t = b[i];
b[i] = b[j];
b[j] = t;
}
}
void PrintElement(TElemType e)
{
b[i++] = e;
}
bool IsSingal(BiTree T) {//判断是否为单叉树
int flag = 1;
while (T) {
if (T->lchild && T->rchild) {
flag = 0;
break;
}
else {
T = T->lchild ? T->lchild : T->rchild;//哪边不空走哪边
}
}
if (flag == 0)
return false;
return true;
}
void compare(TElemType a[], TElemType b[], int n) {
int flag=1;
for (int i = 0; i < n; i++) {
if (a[i] != b[i]) {
flag = 0;
cout << "false";
break;
}
}
if (flag == 1)
cout << "true" ;
}
void PostOrder(BiTree T, void(*Visit)(TElemType)) {//后序遍历
if (T) {
PostOrder(T->lchild,Visit);
PostOrder(T->rchild,Visit);
Visit(T->data);
}
}
int main() {
int count=0,i=0;
TElemType a[100];
BiTree t = NULL;
TElemType e;
while(cin >> e){
a[count++] = e;
InsertBST(t, e);
}
PostOrder(t, PrintElement);
if (IsSingal(t))//如果为单叉树,则不需要逆转数组
compare(a, b, count);
else{
reserve(b, count);
compare(a, b, count);
}
}