数据结构与算法之树、二叉树与森林题目:F二叉树的建立与遍历 G先缀表达式建立二叉树 H中缀表达式建立二叉树 I线索二叉树的构建与遍历 J树的建立与遍历 K森林的建立与遍历 L Huffman树及编码

F

设二叉树的结点的数据域的类型为char,请完成:

(1) 根据带空的先缀串建立一棵二叉树

(2) 输出先序、中序和后序遍历的结果

(3) 输出叶子节点的数量

(4) 输出二叉树的深度

(5) 输出非递归中序遍历的结果

根据题意,对于逻辑结构如下的一棵二叉树而言:

      A
     / \
    B   D
     \
      C

其输入用例为:

AB#C##D##

其输出用例为:

ABCD
BCAD
CBDA
2
3
BCAD

同样,对于如下逻辑结构的二叉树而言:

           -
        /     \
      +        /
     / \      / \
    a   b    d   e

其输入用例为:

-+a##b##/d##e##

其输出用例为:

-+ab/de
a+b-d/e
ab+de/-
4
3
a+b-d/e

用例说明:

(1) 输入用例中'#'表示空树

(2) 输出用例的前三行分别代表三种遍历的结果

(3) 输出用例的第四行表示叶子节点的数量

(4) 输出用例的第五行表示树的深度

(5) 输出用例的第六行表示非递归中序遍历结果

代码:

#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <iomanip>
using namespace std;
struct TreeNode {
    char data;
    TreeNode* left;
    TreeNode* right;

    TreeNode(char d) : data(d), left(nullptr), right(nullptr) {}
};

TreeNode* buildTreeFromPrefixString(std::string& prefix, int& index) {
    if (index >= prefix.length()) {
        return nullptr;
    }

    if (prefix[index] == '#') {
        index++;
        return nullptr;
    }

    TreeNode* newNode = new TreeNode(prefix[index]);
    index++;
    newNode->left = buildTreeFromPrefixString(prefix, index);
    newNode->right = buildTreeFromPrefixString(prefix, index);

    return newNode;
}

void preorderTraversal(TreeNode* root) {
    if (root) {
        std::cout << root->data;
        preorderTraversal(root->left);
        preorderTraversal(root->right);
    }
}

void inorderTraversal(TreeNode* root) {
    if (root) {
        inorderTraversal(root->left);
        std::cout << root->data;
        inorderTraversal(root->right);
    }
}

void postorderTraversal(TreeNode* root) {
    if (root) {
        postorderTraversal(root->left);
        postorderTraversal(root->right);
        std::cout << root->data;
    }
}

int countLeaves(TreeNode* root) {
    if (!root)
        return 0;
    if (!root->left && !root->right)
        return 1;
    return countLeaves(root->left) + countLeaves(root->right);
}

int maxDepth(TreeNode* root) {
    if (!root)
        return 0;
    int leftDepth = maxDepth(root->left);
    int rightDepth = maxDepth(root->right);
    return std::max(leftDepth, rightDepth) + 1;
}

void iterativeInorderTraversal(TreeNode* root) {
    if (!root)
        return;

    std::stack<TreeNode*> stack;
    TreeNode* current = root;

    while (!stack.empty() || current) {
        while (current) {
            stack.push(current);
            current = current->left;
        }

        current = stack.top();
        stack.pop();
        std::cout << current->data;
        current = current->right;
    }
}

int main() {
    std::string input;
    std::cin >> input;

    int index = 0;
    TreeNode* root = buildTreeFromPrefixString(input, index);

    preorderTraversal(root);
    std::cout << std::endl;

    inorderTraversal(root);
    std::cout << std::endl;

    postorderTraversal(root);
    std::cout << std::endl;

    int leafCount = countLeaves(root);
    std::cout << leafCount << std::endl;

    int depth = maxDepth(root);
    std::cout << depth << std::endl;

    iterativeInorderTraversal(root);
    std::cout << std::endl;

    return 0;
}

G

设二叉树的结点的数据域的类型为char,请完成:

(1) 根据先缀表达式建立一棵二叉树

(2) 输出先序、中序和后序遍历的结果

根据题意,对于逻辑结构如下的一棵二叉树而言:

           -
        /     \
      +        /
     / \      / \
    a   b    d   e

其输入用例为:

-+ab/de

其输出用例为:

-+ab/de
a+b-d/e
ab+de/-

用例说明:

(1) 输入用例为先缀表达式串,由字母、+、-、*、/ 构成

(2) 输出用例的三行结果分别代表先序、中序和后序遍历的结果

代码:

#include <iostream>
#include <vector>
#include <string>
#include <stack>
#include <iomanip>
using namespace std;

class TreeNode {
public:
    char data;
    TreeNode* left;
    TreeNode* right;

    TreeNode(char val) {
        data = val;
        left = nullptr;
        right = nullptr;
    }
};

class ExpressionTree {
public:
    TreeNode* buildTreeFromPrefix(string& prefix) {
        int index = 0;
        return buildTreeHelper(prefix, index);
    }

    TreeNode* buildTreeHelper(string& prefix, int& index) {
        if (index >= prefix.size()) {
            return nullptr;
        }

        char currentChar = prefix[index++];
        if (currentChar == '+' || currentChar == '-' || currentChar == '*' || currentChar == '/') {
            TreeNode* node = new TreeNode(currentChar);
            node->left = buildTreeHelper(prefix, index);
            node->right = buildTreeHelper(prefix, index);
            return node;
        }
        else {
            return new TreeNode(currentChar);
        }
    }

    void preOrder(TreeNode* root) {
        if (root) {
            cout << root->data;
            preOrder(root->left);
            preOrder(root->right);
        }
    }

    void inOrder(TreeNode* root) {
        if (root) {
            inOrder(root->left);
            cout << root->data;
            inOrder(root->right);
        }
    }

    void postOrder(TreeNode* root) {
        if (root) {
            postOrder(root->left);
            postOrder(root->right);
            cout << root->data;
        }
    }
};

int main() {
    string prefix;
    cin >> prefix;

    ExpressionTree expressionTree;
    TreeNode* root = expressionTree.buildTreeFromPrefix(prefix);

    expressionTree.preOrder(root);
    cout << endl;

    expressionTree.inOrder(root);
    cout << endl;

    expressionTree.postOrder(root);
    cout << endl;

    return 0;
}

H

设二叉树的结点的数据域的类型为char,请完成:

(1) 根据中缀表达式建立一棵二叉树

(2) 输出先序、中序和后序遍历的结果

根据题意,对于逻辑结构如下的一棵二叉树而言:

       -
    /     \
  +        /
 / \      / \
a   b    d   e

其输入用例为:

(a+b)-d/e

其输出用例为:

-+ab/de
a+b-d/e
ab+de/-

用例说明:

(1) 输入用例为中缀表达式串,由字母、+、-、*、/ 、(、)构成

(2) 输出用例的三行结果分别代表先序、中序和后序遍历的结果

代码:

#include <iostream>
#include <stack>
using namespace std;

// 二叉树节点
struct TreeNode {
    char data;
    TreeNode* left;
    TreeNode* right;
    TreeNode(char val) : data(val), left(nullptr), right(nullptr) {}
};

// 判断运算符的优先级
int precedence(char op) {
    if (op == '*' || op == '/')
        return 2;
    else if (op == '+' || op == '-')
        return 1;
    else
        return 0;
}

// 根据中缀表达式建立二叉树
TreeNode* buildExpressionTree(const string& expression) {
    stack<TreeNode*> nodeStack;
    stack<char> operatorStack;

    for (char c : expression) {
        if (isalpha(c)) {  // 字母结点
            TreeNode* newNode = new TreeNode(c);
            nodeStack.push(newNode);
        }
        else if (c == '(') {  // 左括号入栈
            operatorStack.push(c);
        }
        else if (c == ')') {  // 右括号弹出栈内运算符,构建子树
            while (!operatorStack.empty() && operatorStack.top() != '(') {
                char op = operatorStack.top();
                operatorStack.pop();

                TreeNode* newNode = new TreeNode(op);
                newNode->right = nodeStack.top();
                nodeStack.pop();
                newNode->left = nodeStack.top();
                nodeStack.pop();

                nodeStack.push(newNode);
            }
            operatorStack.pop();  // 弹出左括号
        }
        else if (c == '+' || c == '-' || c == '*' || c == '/') {  // 运算符
            while (!operatorStack.empty() && operatorStack.top() != '(' &&
                precedence(c) <= precedence(operatorStack.top())) {
                char op = operatorStack.top();
                operatorStack.pop();

                TreeNode* newNode = new TreeNode(op);
                newNode->right = nodeStack.top();
                nodeStack.pop();
                newNode->left = nodeStack.top();
                nodeStack.pop();

                nodeStack.push(newNode);
            }
            operatorStack.push(c);  // 当前运算符入栈
        }
    }

    // 处理剩余的运算符
    while (!operatorStack.empty()) {
        char op = operatorStack.top();
        operatorStack.pop();

        TreeNode* newNode = new TreeNode(op);
        newNode->right = nodeStack.top();
        nodeStack.pop();
        newNode->left = nodeStack.top();
        nodeStack.pop();

        nodeStack.push(newNode);
    }

    return nodeStack.top();
}

// 先序遍历二叉树
void preorderTraversal(TreeNode* root) {
    if (root == nullptr)
        return;

    cout << root->data;
    preorderTraversal(root->left);
    preorderTraversal(root->right);
}

// 中序遍历二叉树
void inorderTraversal(TreeNode* root) {
    if (root == nullptr)
        return;

    inorderTraversal(root->left);
    cout << root->data;
    inorderTraversal(root->right);
}

// 后序遍历二叉树
void postorderTraversal(TreeNode* root) {
    if (root == nullptr)
        return;

    postorderTraversal(root->left);
    postorderTraversal(root->right);
    cout << root->data;
}

int main() {
    // 输入中缀表达式
    string expression;
    cin >> expression;

    // 建立二叉树
    TreeNode* root = buildExpressionTree(expression);

    // 输出先序、中序和后序遍历结果
    preorderTraversal(root);
    cout << endl;

    inorderTraversal(root);
    cout << endl;

    postorderTraversal(root);
    cout << endl;

    return 0;
}

I

设二叉树的结点的数据域的类型为char,请完成:

(1) 根据带空的先缀串建立一棵二叉树T

(2) 构建T的中序线索二叉树Thrt

(3) 基于Thrt实现T的中序遍历,并输出遍历结果

(4) 输出Thrt中一度结点的数量

根据题意,对于逻辑结构如下的一棵二叉树而言:

      A
     / \
    B   D
     \
      C

其输入用例为:

AB#C##D##

其输出用例为:

BCAD
2

同样,对于如下逻辑结构的二叉树而言:

           -
        /     \
      +        /
     / \      / \
    a   b    d   e

其输入用例为:

-+a##b##/d##e##

其输出用例为:

a+b-d/e
1

用例说明:

(1) 输入用例中'#'表示空树

(2) 输出用例的第一行代表中序遍历的结果

(3) 输出用例的第二行表示线索二叉树上一度节点的数量

代码:


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct Tree
{
	char data;
	struct Tree* lchild;
	struct Tree* rchild;
	bool left, right;
}Tree, * BitTree;

BitTree createNode(char data)
{
	BitTree newNode = (BitTree)malloc(sizeof(Tree));
	newNode->data = data;
	newNode->lchild = newNode->rchild = NULL;
	newNode->left = newNode->right = false;
	return newNode;
}

BitTree BinaryTree(char s[], int* n)
{
	char c = s[(*n)++];
	if (c == '#')
	{
		return NULL;
	}
	BitTree newNode = createNode(c);
	newNode->lchild = BinaryTree(s, n);
	newNode->rchild = BinaryTree(s, n);
	return newNode;
}

void zhongxuhua(BitTree root, BitTree* prev)
{
	if (root == NULL)
	{
		return;
	}
	zhongxuhua(root->lchild, prev);

	if (root->lchild == NULL)
	{
		root->lchild = *prev;
		root->left = true;
	}

	if (*prev != NULL && (*prev)->rchild == NULL)
	{
		(*prev)->rchild = root;
		(*prev)->right = true;
	}

	*prev = root;

	zhongxuhua(root->rchild, prev);
}

void showzhongxu(BitTree root)
{
	BitTree s1 = root;
	while (s1 != NULL)
	{
		while (!s1->left)
		{
			s1 = s1->lchild;
		}
		printf("%c", s1->data);
		while (s1->right)
		{
			s1 = s1->rchild;
			printf("%c", s1->data);
		}
		s1 = s1->rchild;
	}
}

int Num(BitTree root)
{
	if (root->lchild != NULL && root->rchild != NULL)
		return Num(root->lchild) + Num(root->rchild);
	else if (root->lchild == NULL && root->rchild != NULL)
		return 1 + Num(root->rchild);
	else if (root->lchild != NULL && root->rchild == NULL)
		return 1 + Num(root->lchild);
	return 0;
}

int main()
{
	char s[100];
	int n = 0;
	scanf("%s", s);
	BitTree root = BinaryTree(s, &n);
	int num = Num(root);
	BitTree prev = NULL;
	zhongxuhua(root, &prev);
	showzhongxu(root);
	printf("\n");
	printf("%d", num + 1);
	return 0;
}

J

设树的结点为char类型,请用左孩子右兄弟表示法建树,并完成遍历等操作。

1,以二元组(fa,ch)的形式自上而下、自左而右依次输入树的各边,建立树的孩子-兄弟链表,fa表示ch的父亲,ch是fa的孩子。

2,输出树的先序遍历结果

3,输出树的后序遍历结果

4,输出树的深度

5,输出树中叶子结点的数量

6,输出树中从根到叶子的路径

针对如下所示的树T

                   a
               /   |    \
             b     c      d
            / \    |     / \
            a  i   c    a  u
            |  |   |    |  |
            n  l   e    p  l
            |  |  / \   |  |
            d  i  n  s  t  t
            |  |  |  |
            o  t  t  s
            |  |
            n  y

相应的输入用例为

#,a
a,b
a,c
a,d
b,a
b,i
c,c
d,a
d,u
a,n
i,l
c,e
a,p
u,l
n,d
l,i
e,n
e,s
p,t
l,t
d,o
i,t
n,t
s,s
o,n
t,y
#,#

说明:有序对的第一元为#时,则以第二元为树根;第二元为#时,则表示录入结束。本题中第一行#,A中的第一元为#,则表示第二元A为树根,最后一行#,#中第二元为#,则表示录入结束。

相应的输出用例为

abandonilityccentssdaptult
nodnaytilibtnssecctpatluda
abcdaicaunlepldinsttottsny
7
6
abandon
ability
accent
access
adapt
adult

说明:第一行为先序遍历结果,第二行为后序遍历结果,第三行为层次遍历的结果,第四行为树的深度,第五行为树中叶子结点的数量,第六行一直到最后一行依次输出从根到叶子的路径。

代码:

#include <iostream>
#include <string>
#include <queue>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef char TElemType;

typedef struct TNode
{
    TElemType data;
    struct TNode* lch, * rbro;
}TNode, * Bitree;

TNode* initTree(TElemType e)
{
    TNode* p = new TNode;
    p->data = e;
    p->lch = NULL;
    p->rbro = NULL;
    return p;
}

Bitree creatTree()
{
    queue<Bitree> Q;
    Bitree p;
    string s;
    while (getline(cin, s))
    {
        TElemType u = s[0];
        TElemType v = s[2];

        if (v == '#')
            break;
        if (u == '#') {
            p = initTree(v);
            Q.push(p);
            continue;
        }
        while (Q.front()->data != u)
            Q.pop();
        Bitree p1 = Q.front();
        Bitree p2 = initTree(v);
        Q.push(p2);
        if (p1->lch == NULL)
            p1->lch = p2;
        else
        {
            p1 = p1->lch;
            while (p1->rbro != NULL)
                p1 = p1->rbro;
            p1->rbro = p2;
        }
    }
    return p;
}


void preOrder(Bitree T)
{
    if (T == NULL)
        return;
    //    if(T->data!='/')
    cout << T->data;
    preOrder(T->lch);
    preOrder(T->rbro);
}

void postOrder(Bitree T)
{
    if (T == NULL)
        return;
    postOrder(T->lch);
    //    if(T->data!='/')
    cout << T->data;
    postOrder(T->rbro);
}

void levelOrder(Bitree T)
{
    queue<TNode*> Q;
    Q.push(T);
    while (!Q.empty())
    {
        Bitree p = Q.front();
        Q.pop();
        //        if(p->data!='/')
        cout << p->data;
        if (p->lch != NULL)
        {
            p = p->lch;
            Q.push(p);
            while (p->rbro != NULL)
            {
                Q.push(p->rbro);
                p = p->rbro;
            }
        }
    }
}

int treeDepth(Bitree T)
{
    if (!T) return 0;
    int lh = treeDepth(T->lch) + 1;
    int rh = treeDepth(T->rbro);
    return max(lh, rh);
}

int leafcnt = 0;
void LeafNodes(Bitree T)
{
    if (T == NULL) return;
    if (T->lch == NULL)
        leafcnt++;

    LeafNodes(T->lch);
    LeafNodes(T->rbro);
}

void leafroad(Bitree T, string s)
{
    if (!T) return;
    if (T->lch == NULL)
        cout << s + T->data << endl;
    leafroad(T->lch, s + T->data);
    leafroad(T->rbro, s);

}
int main()
{
    Bitree T = creatTree();
    preOrder(T); cout << endl;
    postOrder(T); cout << endl;
    levelOrder(T); cout << endl;
    cout << treeDepth(T) << endl;
    LeafNodes(T);
    cout << leafcnt << endl;
    leafroad(T, "");
    return 0;
}

K

设森林的结点为char类型,请用左孩子右兄弟表示法建立森林,并完成遍历等操作。

1,以二元组(fa,ch)的形式自上而下、自左而右依次输入森林的各边,建立森林的孩子-兄弟链表,fa表示ch的父亲,ch是fa的孩子。

2,输出森林的先序遍历结果

3,输出森林的中序遍历结果

4,输出森林的深度

5,输出森林中叶子结点的数量

6,输出森林中各棵树从根到叶子的路径

针对如下所示的森林F,分别由以a,b,c为根的三棵树构成:

                   a            b            c
              /    |      \     |           / \
             b     c      d     o           a h
            / \    |     / \   / \          | |
            a  i   c    a  u   b y          t i
            |  |   |    |  |                  |
            n  l   e    p  l                  n
            |  |  / \   |  |                  |
            d  i  n  s  t  t                  a
            |  |  |  |
            o  t  t  s
            |  |
            n  y

在构建时候,可以增加一个根结点,将森林改造成一个树,然后按照树的构建算法完成森林的创建。 比如用'/'表示增加的根节点,则森林F改造成的树为:

                                /
                        /       |       \
                       /        |        \
                      /         |         \
                     /          |          \
                    /           |           \
                   a            b            c
              /    |      \     |           / \
             b     c      d     o           a h
            / \    |     / \   / \          | |
            a  i   c    a  u   b y          t i
            |  |   |    |  |                  |
            n  l   e    p  l                  n
            |  |  / \   |  |                  |
            d  i  n  s  t  t                  a
            |  |  |  |
            o  t  t  s
            |  |
            n  y

据此,相应的输入用例为

#,/
/,a
/,b
/,c
a,b
a,c
a,d
b,o
c,a
c,h
b,a
b,i
c,c
d,a
d,u
o,b
o,y
a,t
h,i
a,n
i,l
c,e
a,p
u,l
i,n
n,d
l,i
e,n
e,s
p,t
l,t
n,a
d,o
i,t
n,t
s,s
o,n
t,y
#,#

说明:第一行#,/表示/为树根,最后一行#,#表示录入结束

相应的输出用例为

abandonilityccentssdaptultbobycathina
nodnaytilibtnssecctpatludabyobtaanihc
abcbcdoahaicaubytinleplndinsttaottsny
7
10
abandon
ability
accent
access
adapt
adult
bob
boy
cat
china

说明:第一行为先序遍历森林的结果,第二行为中序遍历森林的结果,第三行为按层次遍历森林的结果,第四行为森林的深度,第五行为森林中叶子结点的数量,第六行一直到最后一行依次输出森林中各个树根到叶子的路径

再如:针对如下所示的森林F,分别由以B,C,D为根的三棵树构成

            B C D
             / \
             E F
             |
             G

在构建时候,用'/'作为增加的根节点,将森林F改造成的树为:

              /
            / | \
            B C D
             / \
             E F
             |
             G

相应的输入用例为

#,/
/,B
/,C
/,D
C,E
C,F
E,G
#,#

相应的输出用例为

BCEGFD
BGEFCD
BCDEFG
3
4
B
CEG
CF
D

总结:通过本例可见,树和森林的构建及遍历操作可以说是一样的,没有本质区别。

代码:

#include <iostream>
#include <string>
#include <queue>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef char TElemType;

typedef struct TNode
{
    TElemType data;
    struct TNode* lch, * rbro;
}TNode, * Bitree;

TNode* initTree(TElemType e)
{
    TNode* p = new TNode;
    p->data = e;
    p->lch = NULL;
    p->rbro = NULL;
    return p;
}

Bitree creatTree()
{
    queue<Bitree> Q;
    Bitree p;
    string s;
    while (getline(cin, s))
    {
        TElemType u = s[0];
        TElemType v = s[2];

        if (v == '#')
            break;
        if (u == '#') {
            p = initTree(v);
            Q.push(p);
            continue;
        }
        while (Q.front()->data != u)
            Q.pop();
        Bitree p1 = Q.front();
        Bitree p2 = initTree(v);
        Q.push(p2);
        if (p1->lch == NULL)
            p1->lch = p2;
        else
        {
            p1 = p1->lch;
            while (p1->rbro != NULL)
                p1 = p1->rbro;
            p1->rbro = p2;
        }
    }
    return p;
}


void preOrder(Bitree T)
{
    if (T == NULL)
        return;
    if (T->data != '/')
        cout << T->data;
    preOrder(T->lch);
    preOrder(T->rbro);
}

void postOrder(Bitree T)
{
    if (T == NULL)
        return;
    postOrder(T->lch);
    if (T->data != '/')
        cout << T->data;
    postOrder(T->rbro);
}

void levelOrder(Bitree T)
{
    queue<TNode*> Q;
    Q.push(T);
    while (!Q.empty())
    {
        Bitree p = Q.front();
        Q.pop();
        if (p->data != '/')
            cout << p->data;
        if (p->lch != NULL)
        {
            p = p->lch;
            Q.push(p);
            while (p->rbro != NULL)
            {
                Q.push(p->rbro);
                p = p->rbro;
            }
        }
    }
}

int treeDepth(Bitree T)
{
    if (!T) return 0;
    int lh = treeDepth(T->lch) + 1;
    int rh = treeDepth(T->rbro);
    return max(lh, rh);
}

int leafcnt = 0;
void LeafNodes(Bitree T)
{
    if (T == NULL) return;
    if (T->lch == NULL)
        leafcnt++;

    LeafNodes(T->lch);
    LeafNodes(T->rbro);
}

void leafroad(Bitree T, string s)
{
    if (!T) return;
    if (T->lch == NULL) {
        string ss;
        for (int i = 1; i < s.size(); ++i)
            ss = ss + s[i];
        cout << ss + T->data << endl;

    }
    leafroad(T->lch, s + T->data);
    leafroad(T->rbro, s);

}
int main()
{
    Bitree T = creatTree();
    preOrder(T); cout << endl;
    postOrder(T); cout << endl;
    levelOrder(T); cout << endl;
    cout << treeDepth(T) - 1 << endl;
    LeafNodes(T);
    cout << leafcnt << endl;
    leafroad(T, "");
    return 0;
}

L

输入一个全部由小写英文字母和空格构成的字符串str,串长≤256,请完成:

1,统计str中各个小写字母的频率

2,以按各个小写字母升序排列的频率作为初态,构造一棵最优二叉树T

3, 计算各个字母的最佳编码,编码用0和1表示,编码约定:对于T上的所有分支,左分支取0,右分支取1

4,计算str的最优码长(计算T的带权路径长度)

用例1

hello
e(1)00
h(1)01
l(2)11
o(1)10
10

用例2

hello every one
e(4)10
h(1)1110
l(2)011
n(1)1111
o(2)110
r(1)000
v(1)001
y(1)010
37

用例3

hello every one my name is tom
a(1)11100
e(5)00
h(1)11101
i(1)11110
l(2)1011
m(3)011
n(2)1100
o(3)100
r(1)11111
s(1)0100
t(1)0101
v(1)1010
y(2)1101
84

用例说明:

第1行表示输入的字符串str

第2行到倒数第2行按字母升序顺序输出各个字母及其出现频率和最佳编码,其中频率用英文状态下的小括号括起来

最后1行输出字符串str的最优码长

为了加深理解题意,下面分别给出用例1和用例2的分析过程

用例1分析:

首先,对输入的hello串进行统计,可得h出现了1次,e出现了1次,l出现了2次,o出现了1次,

可得各个字母的频率按字母升序排列的结果为: e(1) h(1) l(2) o(1)

然后,据此构造最优二叉树的过程如下:

初态:
  结点  weight  parent  lchild  rchild  字母    初态对应如下4个森林
   1       1       0       0       0      e     e(1)  h(1)  l(2)  o(1)
   2       1       0       0       0      h
   3       2       0       0       0      l
   4       1       0       0       0      o
   5       0       0       0       0
   6       0       0       0       0
   7       0       0       0       0

select: s1=1   s2=2
  结点  weight  parent  lchild  rchild  字母    当前格局对应的森林为
   1       1       5       0       0      e     l(2)  o(1)      2
   2       1       5       0       0      h                   /   \
   3       2       0       0       0      l                 e(1)  h(1)
   4       1       0       0       0      o
   5       2       0       1       2

select: s1=4   s2=3
  结点  weight  parent  lchild  rchild  字母    当前格局对应的森林为
   1       1       5       0       0      e                      2          3
   2       1       5       0       0      h                    /   \      /   \
   3       2       6       0       0      l                  e(1)  h(1) o(1)  l(2)
   4       1       6       0       0      o
   5       2       0       1       2
   6       3       0       4       3

select: s1=5   s2=6
  结点  weight  parent  lchild  rchild  字母    当前格局对应的最优二叉树为
   1       1       5       0       0      e                5
   2       1       5       0       0      h            /       \
   3       2       6       0       0      l           2         3
   4       1       6       0       0      o          /  \      /  \
   5       2       7       1       2               e(1) h(1) o(1)  l(2)
   6       3       7       4       3
   7       5       0       5       6

根据约定,由这棵最优二叉树可得e的编码为00,h的编码为01,o的编码为10,l的编码为11,

故最优码长为:2X1+2X1+2X1+2X2=10

注意:select的功能:从上一格局中选择parent为0且weight最小的两个结点,第一小的结点下标为s1,次小的下标为s2,且s1作为新子树根的左子树,s2作为右子树

用例2分析:

首先,对输入的hello every one串进行统计,可得h出现了1次,e出现了4次,l出现了2次,o出现了2次,v出现了1次,r出现了1次,y出现了1次,n出现了1次,

可得各个字母的频率按字母升序排列的结果为: e(4) h(1) l(2) n(1) o(2) r(1) v(1) y(1)

然后,据此构造最优二叉树的过程如下:

初态:
  结点  weight  parent  lchild  rchild  字母    初态对应如下8个森林

   1       4       0       0       0     e      e(4)  h(1)  l(2)  n(1)  o(2)  r(1)  v(1)  y(1)
   2       1       0       0       0     h
   3       2       0       0       0     l
   4       1       0       0       0     n
   5       2       0       0       0     o
   6       1       0       0       0     r
   7       1       0       0       0     v
   8       1       0       0       0     y
   9       0       0       0       0
  10       0       0       0       0
  11       0       0       0       0
  12       0       0       0       0
  13       0       0       0       0
  14       0       0       0       0
  15       0       0       0       0


select: s1=2   s2=4
  结点  weight  parent  lchild  rchild   字母    当前格局对应的森林为
   1       4       0       0       0      e      e(4)  l(2)  o(2)  r(1)  v(1)  y(1)  2
   2       1       9       0       0      h                                        /   \
   3       2       0       0       0      l                                      h(1)  n(1)
   4       1       9       0       0      n
   5       2       0       0       0      o
   6       1       0       0       0      r
   7       1       0       0       0      v
   8       1       0       0       0      y
   9       2       0       2       4

select: s1=6   s2=7
  结点  weight  parent  lchild  rchild   字母    当前格局对应的森林为
   1       4       0       0       0      e      e(4)  l(2)  o(2)  y(1)    2           2
   2       1       9       0       0      h                              /   \       /   \
   3       2       0       0       0      l                            h(1)  n(1)  r(1)  v(1)
   4       1       9       0       0      n
   5       2       0       0       0      o
   6       1      10       0       0      r
   7       1      10       0       0      v
   8       1       0       0       0      y
   9       2       0       2       4
  10       2       0       6       7

select: s1=8   s2=3
  结点  weight  parent  lchild  rchild   字母    当前格局对应的森林为
   1       4       0       0       0      e      e(4)   o(2)      2           2         3
   2       1       9       0       0      h                     /   \       /   \     /   \
   3       2      11       0       0      l                  h(1)  n(1)  r(1)  v(1) y(1)  l(2)
   4       1       9       0       0      n
   5       2       0       0       0      o
   6       1      10       0       0      r
   7       1      10       0       0      v
   8       1      11       0       0      y
   9       2       0       2       4
  10       2       0       6       7
  11       3       0       8       3

select: s1=5   s2=9
  结点  weight  parent  lchild  rchild  字母    当前格局对应的森林为
   1       4       0       0       0      e     e(4)             2             3              4
   2       1       9       0       0      h                    /   \         /   \          /   \
   3       2      11       0       0      l                   r(1)  v(1)   y(1) l(2)     o(2)    2
   4       1       9       0       0      n                                                    /   \
   5       2      12       0       0      o                                                 h(1)  n(1)
   6       1      10       0       0      r
   7       1      10       0       0      v
   8       1      11       0       0      y
   9       2      12       2       4
  10       2       0       6       7
  11       3       0       8       3
  12       4       0       5       9

select: s1=10   s2=11
  结点  weight  parent  lchild  rchild  字母    当前格局对应的森林为
   1       4       0       0       0     e      e(4)           4                            5
   2       1       9       0       0     h                    /   \                   /            \
   3       2      11       0       0     l                o(2)    2                  2             3
   4       1       9       0       0     n                      /   \              /   \         /   \
   5       2      12       0       0     o                   h(1)  n(1)           r(1)  v(1)   y(1) l(2)
   6       1      10       0       0     r
   7       1      10       0       0     v
   8       1      11       0       0     y
   9       2      12       2       4
  10       2      13       6       7
  11       3      13       8       3
  12       4       0       5       9
  13       5       0      10      11


select: s1=1   s2=12
  结点  weight  parent  lchild  rchild  字母    当前格局对应的森林为
   1       4      14       0       0     e                     5                        8
   2       1       9       0       0     h              /            \           /            \
   3       2      11       0       0     l              2             3       e(4)            4
   4       1       9       0       0     n            /   \         /   \                   /   \
   5       2      12       0       0     o           r(1)  v(1)   y(1) l(2)                o(2)  2
   6       1      10       0       0     r                                                     /   \
   7       1      10       0       0     v                                                   h(1)  n(1)
   8       1      11       0       0     y
   9       2      12       2       4
  10       2      13       6       7
  11       3      13       8       3
  12       4      14       5       9
  13       5       0      10      11
  14       8       0       1      12

select: s1=13   s2=14
  结点  weight  parent  lchild  rchild  字母    当前格局对应的最优二叉树为
   1       4      14       0       0     e                                             13
   2       1       9       0       0     h                                         /        \
   3       2      11       0       0     l                                        5          8
   4       1       9       0       0     n                                    /       \    /   \
   5       2      12       0       0     o                                   2        3  e(4)   4
   6       1      10       0       0     r                                 /   \     /   \     /   \
   7       1      10       0       0     v                              r(1) v(1) y(1) l(2)  o(2)  2
   8       1      11       0       0     y                                                       /   \
   9       2      12       2       4                                                          h(1)  n(1)
  10       2      13       6       7
  11       3      13       8       3
  12       4      14       5       9
  13       5      15      10      11
  14       8      15       1      12
  15      13       0      13      14

根据约定,由这棵最优二叉树可得r的编码为000,v的编码为001,y的编码为010,l的编码为011,o的编码为110,h的编码为1110,n的编码为1111,

故最优码长为:3X1+3X1+3X1+3X2+2X4+2X3+4X1+4X1=37

注意:select的功能:从上一格局中选择parent为0且weight最小的两个结点,第一小的结点下标为s1,次小的下标为s2,且s1作为新子树根的左子树,s2作为右子树

#include <iostream>
#include <string>
using namespace std;
/*
    1.根据输入字符进行字符处理同时将字母的频率记录
    2.创建Huffman树
    3.huffmancode
    4.统计总数

*/
typedef char ElemType;
int cnt[26];
int HFNum;
string coding[26];

typedef struct
{
    ElemType data;
    int parent,lch,rch;
    int weight;
}HFNode,*HuffmanTree;

HFNode HF[1000];

void InitHuffman()
{
    HFNum=0;
    for(int i=0;i<26;++i)
    {
        if(cnt[i]==0)
            continue;
        HF[HFNum].parent = HF[HFNum].lch = HF[HFNum].rch = -1;
        HF[HFNum].data = 'a'+ i;
        HF[HFNum].weight = cnt[i];
        HFNum++;
    }

}
void createHuffmanTree()
{
    int s1,s2;
    int min1,min2;
    for(int i=HFNum;i<2*HFNum-1;++i)
    {
        s1=s2=-1;
        min1 = min2 = 10086;
        HF[i].parent = HF[i].lch = HF[i].rch = -1;

        for(int j=0;j<i;++j)
        {
            if(HF[j].weight<min1&&HF[j].parent==-1)
            {
                min2 = min1; s2 = s1;
                min1 = HF[j].weight; s1 = j;
            }
            else if(HF[j].weight<min2&&HF[j].parent==-1)
            {
                min2 = HF[j].weight;
                s2 = j;
            }
        }

        HF[s1].parent = i;HF[s2].parent = i;
        HF[i].lch = s1;HF[i].rch = s2;
        HF[i].weight = HF[s1].weight + HF[s2].weight;

    }

}

void createHFCode()
{
   int c,f;
   for(int i=0;i<HFNum;++i)
   {
       int pos = HF[i].data - 'a';
       string code = "";
       c = i;
       f = HF[c].parent;
       while(f!=-1)
       {
           if(HF[f].lch==c)
            code = '0' + code;
           else
            code = '1' + code;
           c = f;
           f = HF[f].parent;
       }
       coding[pos] = code;
   }
}

void show()
{
    int sum=0;
    for(int i=0;i<26;i++)
    {
        if(cnt[i]==0)
            continue;
        int temp= cnt[i]*coding[i].size();
        sum+=temp;
        printf("%c(%d)",'a'+i,cnt[i]);
        cout<<coding[i]<<endl;
    }
    cout<<sum<<endl;
}
int main()
{
    string s;
    getline(cin,s);
    for(unsigned int i = 0;i<s.length();++i)
        if(s[i]!=' ')
            cnt[s[i]-'a']++;
    InitHuffman();
    createHuffmanTree();
    createHFCode();
    show();

    return 0;
}

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 要将一个表达式二叉树转换成中缀,可以按照以下步骤进行: 1. 对于叶子节点,直接将节点的值作为中缀表达式的一个操作数。 2. 对于非叶子节点,如果节点的值是一个运算符,则将其左子和右子分别转换成中缀表达式,并将它们与当前节点的运算符拼接成一个完整的中缀表达式。 3. 如果当前节点的值不是运算符,则直接将其值作为中缀表达式的一个操作数。 4. 最终得到的中缀表达式即为中缀。 举例说明,假设有以下的表达式二叉树: ``` * / \ + 5 / \ 3 4 ``` 按照上述步骤进行转换,可以得到以下的中缀: ``` __*__ / \ + 5 / \ 3 4 ``` 其中,中缀表达式为:3 + 4 * 5。 ### 回答2: 表达式二叉树转换成中缀是将一个以表达式二叉树表示的数学表达式转换为中缀表达式的过程。 要将表达式二叉树转换为中缀,可以使用递归的方法进行操作。首先,我们需要理解表达式二叉树的结构。 表达式二叉树是一种二叉树,其中每个节点都可以是操作符或操作数。操作符节点的左子和右子分别代表了操作符的两个操作数,而操作数节点则没有子节点。 要将表达式二叉树转换为中缀,可以按照以下步骤进行操作: 1. 若当前节点为操作数节点,则直接返回该节点的值作为中缀表达式的一个操作数。 2. 若当前节点为操作符节点,则需要将其左子和右子分别转换为中缀表达式,并用当前节点的值将它们连接起来。 3. 需要注意的是,由于中缀表达式要求操作符的顺序和优先级,需要添加一些括号来确保正确计算。具体来说,如果当前节点的操作符比其左子节点的操作符优先级低,则需要在左子节点的中缀表达式前后添加括号。如果当前节点的操作符比其右子节点的操作符优先级低(或相等),则只需要在右子节点的中缀表达式前后添加括号。 4. 最后,将经过上述操作得到的中缀表达式返回。 通过以上步骤,我们可以将表达式二叉树转换为对应的中缀。这样做的好处是方便理解和运算,同时也符合数学表达式的规范形式。 ### 回答3: 表达式二叉树是一种用二叉树表示数学表达式的结构,其中每个节点都是操作符或操作数。要将表达式二叉树转换成中缀表达式,需要遵循以下步骤: 1. 从根节点开始遍历二叉树。如果当前节点是操作数,则直接将其值作为中缀表达式的一个值。 2. 如果当前节点是操作符,则将其值添加到中缀表达式中。 3. 检查当前节点的左右子节点。如果子节点也是操作符,则使用括号将它们括起来,并将其添加到中缀表达式中。 4. 重复步骤1-3,直到遍历结束并生成完整的中缀表达式。 例如,考虑以下表达式二叉树: + / \ * 3 / \ 2 5 从根节点开始遍历,首先遇到操作符'+', 将其添加到中缀表达式中,得到'+'。 然后检查左子节点,发现是操作符'*',将其添加到中缀表达式,现在表达式变为'*+'。 然后检查左子节点的左子节点,发现是操作数2,将其添加到中缀表达式中,现在表达式为'2*+'。 然后检查左子节点的右子节点,发现是操作数5,将其添加到中缀表达式中,得到'2*5+'。 最后检查根节点的右子节点,发现是操作数3,将其添加到中缀表达式中,最终得到完整的中缀表达式'2*5+3'。 通过以上步骤,我们可以将表达式二叉树转换成中缀表达式

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值