广州大学学生实验报告,数据结构实验,二叉树的操作与实现

广州大学学生实验报告

开课学院及实验室: 计算机科学与工程实验室 418              2022年10月3日

学院

计算机科学与网络工程

年级、专业、班

计科

姓名

Great

Macro

学号

实验课程名称

数据结构实验

成绩

实验项目名称

二叉树的操作与实现

指导老师

  • 实验目的

1.掌握树的定义、相关术语、性质;

2.掌握二叉树的定义、相关性质以及与树的关系;

3. 设计与实现二叉树上的基本操作。

  • 使用仪器、器材

1. 微机一台

2. 操作系统:WINXP / wiin8 / win10

3. 编程软件:C / C++ / JAVA

  • 实验内容及原理

//描述具体做什么,算法原理、做法

内容:

树是非线性结构,多用链式结构实现。二叉树是结点度不超过2,分支间有左右之分的特殊树。树乃至森林都可以由二叉树唯一地表达。本实验在于加深学生对树或二叉树抽象数据类型有关要素(数据对象、数据关系、以及创建、表示、插入、删除、遍历、查找、深度/宽度计算)的认识(参见《数据结构》教材第5章有关内容)。这里要求定义好树/二叉树的输入表示,至少实现其创建、遍历、深度/宽度计算、相关递归算法等基本操作的计算问题。

原理:

typedef char DataType;//定义数据类型

typedef struct BiTNode {//定义二叉树结构

DataType data;

BiTNode* lchild, * rchild;

}BiTNode, * BiTree;

void CreateBiTree(BiTree& T) {//创建二叉树

DataType ch;

cin >> ch;

if (ch == '#')T = NULL;

else {

T = new BiTNode;

T->data = ch;

CreateBiTree(T->lchild);//创建左子树

CreateBiTree(T->rchild);//创建右子树

}

}

void PreOrderTraverse(BiTree T) {//先序遍历

if (T) {

cout << T->data;//访问结点

PreOrderTraverse(T->lchild);//遍历左子树

PreOrderTraverse(T->rchild);//遍历右子树

}

}

void PreOrderTraverse_2(BiTree T) {

SqStack S;

InitStack(S);

BiTree p;

if (T)Push(S, T);

while (!StackEmpty(S)) {

Pop(S, p);

cout << p->data;//访问结点

if (p->rchild)Push(S, p->rchild);//遍历右子树

if (p->lchild)Push(S, p->lchild);//遍历左子树

}

}

void PreOrderTraverse_3(BiTree T) {

SqStack S;

InitStack(S);

BiTree p = T;

while (p || !StackEmpty(S)) {

if (p) {//查找最左子树

cout << p->data;//访问结点

Push(S, p);

p = p->lchild;

}

else {//遍历右子树

Pop(S, p);

p = p->rchild;

}

}

}

void InOrderTraverse(BiTree T) { //中序遍历

if (T) {

InOrderTraverse(T->lchild);//遍历左子树

cout << T->data;  //访问结点

InOrderTraverse(T->rchild);//遍历右子树

}

}

void InOrderTraverse_2(BiTree T) {

SqStack S;

InitStack(S);

BiTree p = T;

while (p || !StackEmpty(S)) {

if (p) {

Push(S, p);

p = p->lchild;//遍历左子树

}

else {

Pop(S, p);

cout << p->data;//访问结点

p = p->rchild;//遍历右子树

}

}

}

void PostOrderTraverse(BiTree T) {//后序遍历

if (T) {

PostOrderTraverse(T->lchild);//遍历左子树

PostOrderTraverse(T->rchild);//遍历右子树

cout << T->data;//访问结点

}

}

void PostOrderTraverse_2(BiTree T) {

SqStack S;

InitStack(S);

BiTree p = T;

BiTree q = NULL;

while (p || !StackEmpty(S)) {

if (p) {

Push(S, p);

p = p->lchild;//遍历最左子树

}

else {

p = GetTop(S);

if (p->rchild && p->rchild != q) {

p = p->rchild;

}

else {

Pop(S, p);

cout << p->data;//访问结点

q = p;

p = NULL;

}

}

}

}

void LevelOrderTraverse(BiTree T) {

SQueue Q;

InitQueue(Q);

if (T)EnQueue(Q,T);

while (!QueueEmpty(Q)) {

BiTree t=GetHead(Q);

DeQueue(Q,t);

cout << t->data;//访问结点

if (t->lchild)EnQueue(Q,t->lchild);//左孩子进队

if(t->rchild)EnQueue(Q, t->rchild);//右孩子进队

}

DestroyQueue(Q);//释放空间

}

void BiTreeCopy(BiTree T, BiTree& NewT) {//复制二叉树

if (T == NULL) NewT = NULL;

else {

NewT = new BiTNode;

NewT->data = T->data;//复制结点

BiTreeCopy(T->lchild, NewT->lchild);//复制左子树

BiTreeCopy(T->rchild, NewT->rchild);//复制右子树

}

}

int BiTreeDepth(BiTree T) {//计算二叉树的深度

if (!T)return 0;

else {

int m = BiTreeDepth(T->lchild);//左子树深度

int n = BiTreeDepth(T->rchild);//右子树深度

if (m > n)return m + 1;//返回最大的深度

else return n + 1;

}

}

int BiTreeWidth(BiTree T) {//计算二叉树的宽度

if(!T)return 0;

else {

int n= BiTreeDepth(T);

int* num = new int[n];//给每一层分配一个空间记录该层结点数目

for (int i = 0; i < n; i++)

num[i] = 0;//初始化每层的结点数目为0

SQueue Q;

InitQueue(Q);

if (T) { EnQueue(Q, T);};

for (int j = 0; j < n && !QueueEmpty(Q); j++) {

num[j]= QueueLength(Q);//记录每层的结点数目

for (int i = 0; i < num[j]; i++) {//弹出上一层所有结点,并将下一层所有结点进队

BiTree p=GetHead(Q);

DeQueue(Q, p);

if (p->lchild)EnQueue(Q, p->lchild);//左孩子进队

if (p->rchild)EnQueue(Q, p->rchild);//右孩子进队

}

}

int max = num[0];

for (int i = 1; i < n; i++) {//比较最大宽度

if (num[i] > max)max = num[i];

}

delete []num;

return max;

}

}

int NodeCount(BiTree T) {//计算二叉树中的结点的个数

if (T == NULL)return 0;

else return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;

}

int NodeCount_0(BiTree T) {//计算二叉树中的叶结点

if (T == NULL)return 0;

else if (!T->lchild && !T->rchild)return 1;

else return NodeCount_0(T->lchild) + NodeCount_0(T->rchild);

}

int NodeCount_1(BiTree T) {

// 计算二叉树中度数为1的结点数目

if (T == NULL)return 0;

if (!T->lchild&& T->rchild || T->lchild&&!T->rchild)

return NodeCount_1(T->lchild) + NodeCount_1(T->rchild) + 1;

else return NodeCount_1(T->lchild) + NodeCount_1(T->rchild);

}

int NodeCount_2(BiTree T) {

// 计算二叉树中度数为2的结点数目

if (T == NULL)return 0;

if (T->lchild && T->rchild)return NodeCount_2(T->lchild) + NodeCount_2(T->rchild)+1;

else return NodeCount_2(T->lchild) + NodeCount_2(T->rchild);

}

DataType BiTreeRoot(BiTree T) {//返回根结点

if (!T)return '0';

return T->data;

}

bool  DestroyBiTree(BiTree& T) {

if (T) {

DestroyBiTree(T->lchild);//删除左子树

DestroyBiTree(T->rchild);//删除右子树

delete T;

return true;

}

else return false;

}

bool ClearBiTree(BiTree &T) {

if (T) {

ClearBiTree(T->lchild);//清空左子树

ClearBiTree(T->rchild);//清空右子树

T = NULL;

return true;

}

return false;

}

bool CheckBiTree(BiTree T,DataType data) {

if (!T)return false;

else {

if (T->data == data) {//查找到结点

return true;

}//查找左子树和右子树

return CheckBiTree(T->lchild, data) || CheckBiTree(T->rchild, data);

}

}

bool BiTreeEmpty(BiTree T) {//判断二叉树是否为空

if (!T)return true;

else return false;

}

int InsertChild(BiTree& T, DataType parentdata, DataType newdata,int LR) {

if (!T)return 0;

else {

if (T->data == parentdata) {

BiTNode* child = new BiTNode;

child->data = newdata;

child->lchild = NULL;

if (LR == 0) {//插入左子树

BiTNode* q = T->lchild;

child->rchild = q;

T->lchild = child;

}

else {//插入右子树

BiTNode* s = T->rchild;

child->rchild = s;

T->rchild = child;

}

return 1;

}//查找左右子树并插入

return InsertChild(T->lchild, parentdata, newdata, LR) + InsertChild(T->rchild, parentdata, newdata, LR);

}

}

int DeleteChild(BiTree& T, DataType parentdata, int LR) {

if (!T)return 0;

else {

if (T->data == parentdata) {//查找双亲结点

if (LR == 0) {

DestroyBiTree(T->lchild);//删除左子树

T->lchild = NULL;

}

else {

DestroyBiTree(T->rchild);//删除右子树

T->rchild = NULL;

}

return 1;

}

return DeleteChild(T->lchild, parentdata, LR)+DeleteChild(T->rchild,parentdata,LR);

}

}

哈夫曼树与编码:

typedef struct {

    int weight;

    int parent, lchild, rchild;

}HTNode,*HuffmanTree;

void Select(HuffmanTree HT, int n, int& s1, int& s2)  {

    if (n <= 1)return;

    int i;

    int k = 0;

    int* w= new int[n+1];

    for (i = 0; i < n; i++)

        w[i] = 0;

    for (i = 1; i <= n; i++) {

        if (!HT[i].parent )

             w[k++]=i;//w[k]为双亲为0的结点序号

    }

    if (w[0] || w[1]) {

        s1 = w[0];

        for (i = 1; i < k; i++)

            if (HT[w[i]].weight < HT[s1].weight)s1 = w[i];//选择最小的

        for (i = 0; i < k; i++)

            if (w[i] != s1) { s2 = w[i]; break; }

        for (i = 0; i < k; i++)

            if (HT[w[i]].weight < HT[s2].weight && w[i]!= s1)s2 = w[i];//选择第二小的

    }

    delete[]w;

}

void CreateHuffmanTree(HuffmanTree& HT, int n) {

    if (n <= 1)return;

    int m = 2 * n - 1;

    HT = new HTNode[m + 1];

    for (int i = 1; i <= m; i++) {//初始化

        HT[i].parent = 0;

        HT[i].lchild = 0;

        HT[i].rchild = 0;

    }

    for (int i = 1; i <= n; i++) {

        cin >> HT[i].weight;

    }

    cout << "构造哈夫曼树:" << endl;

    for (int i = n + 1; i <= m; i++) {//选择剩下的结点

        int s1 = 0;

        int s2 = 0;

        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;

        cout<<"原来的两个结点:"<< HT[s1].weight << " " << HT[s2].weight <<"  新的结点:"<<HT[i].weight<<endl;    }

}

void Copy(char *HC, int start, int end, char* cd) {//复制编码

    for (int i = 0;i<end-start-1; i++)

        HC[i] = cd[start+i];

    HC[end - start-1] = '\0';

}

typedef char** HuffmanCode;

void CreateHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n) {

    HC = new char* [n + 1];

    char *cd = new char[n];

    cd[n - 1] = '\0';

    for (int i = 1; i <= n; i++) {//向上回溯

        int start = n - 1;

        int c = i;

        int f = HT[i].parent;

        while (f != 0) {

            --start;

            if (HT[f].lchild == c)cd[start] = '0';//左孩子为0

            else cd[start] = '1';//右孩子为1

            c = f;

            f = HT[f].parent;

        }

        HC[i] = new char[n - start];

        Copy(HC[i], start, n, cd);

    }

    delete[]cd;

}

  • 实验过程原始数据记录

//代码及调试信息、截屏说明

测试函数:

void test(BiTree& T) {

cout << "请选择对二叉树的操作:" << endl;

cout << "A.创建 B.遍历 C.插入 D.删除 E.查树 F.查根 G.清空 H.销毁 I.退出 " << endl;

char choice;

int key = 0;

cin >> choice;

while (1) {

if (choice == 'A') {

key = 1;

cout << "采用先序遍历的顺序建立二叉链表,以#结束输入 " << endl;;

CreateBiTree(T);

cout << "创建成功!" << endl;

}

if (choice == 'I') { cout << "你已退出!" << endl; break; }

if (!key && choice != 'H') { cout << "该树不存在!请先创建一个树!" << endl; }

cout << "请选择对二叉树的操作:" << endl;

cout << "A.创建 B.遍历 C.插入 D.删除 E.查树 F.查根 G.清空 H.销毁 I.退出 " << endl;

cin >> choice;

if (choice < 'A' || choice>'I') {

cout << "输入不合法!请重新输入:";

cin >> choice;

}

if (key) {

switch (choice) {

case 'B':

if (BiTreeEmpty(T))cout << "这是一棵空树!" << endl;

else {

cout << "请选择遍历方式:a.先序遍历 b.中序遍历 c.后序遍历 d.层次遍历" << endl;

cin >> choice;

switch (choice) {

case 'a':cout << "先序遍历结果:"; PreOrderTraverse_3(T); break;

case 'b':cout << "中序遍历结果:"; InOrderTraverse_2(T); break;

case 'c':cout << "后序遍历结果:"; PostOrderTraverse(T); break;

case 'd':cout << "层次遍历结果:"; LevelOrderTraverse(T); break;

}

cout << endl;

}

 break;

case 'C':

if (BiTreeEmpty(T))cout << "这是一棵空树!" << endl;

else {

cout << "请输入想插入的结点的双亲:";

DataType a;

cin >> a;

if (CheckBiTree(T, a)) {

cout << "请输入插入的结点的元素:";

DataType b;

cin >> b;

cout << "请选择插入结点的类型:0.左孩子 1.右孩子: ";

int LR;

cin >> LR;

InsertChild(T, a,b, LR);

cout << "插入成功!" << endl;

}

else cout << "二叉树中不存在该结点!" << endl;

}

break;

case 'D':

if (BiTreeEmpty(T))cout << "这是一棵空树!" << endl;

else {

cout << "请输入想删除子树的双亲:";

DataType c;

cin >> c;

if (CheckBiTree(T, c)) {

cout << "请选择删除结点的子树:0.左子树 1.右子树: ";

int LR;

cin >> LR;

DeleteChild(T, c, LR);

cout << "删除成功!" << endl;

}

}

break;

case 'E':

if (BiTreeEmpty(T))cout << "这是一棵空树!" << endl;

else {

cout << "请选择查找的操作:a.宽度 b.深度 c.结点数目 d.叶结点数目 e.度数为1的结点的数目 f.度数为2的结点的数目" << endl;

cin >> choice;

switch (choice) {

case 'a':cout << "该二叉树的宽度是: " << BiTreeWidth(T) << endl; break;

case 'b':cout << "该二叉树的深度是: " << BiTreeDepth(T) << endl; break;

case 'c':cout << "该二叉树的结点数目:" << NodeCount(T) << endl; break;

case 'd':cout << "该二叉树的叶结点数目:" << NodeCount_0(T) << endl; break;

case 'e':cout << "该二叉树度数为1的结点数目:" << NodeCount_1(T) << endl; break;

case 'f':cout << "该二叉树度数为2的结点数目:" << NodeCount_2(T) << endl; break;

}

 break;

case 'F':

if (BiTreeEmpty(T))cout << "这是一棵空树!" << endl;

else cout << "该二叉树的根结点是: " << BiTreeRoot(T) << endl;

break;

case 'G':

if (BiTreeEmpty(T))cout << "这是一棵空树!" << endl;

else {

ClearBiTree(T);

cout << "清空成功!" << endl;

}

 break;

case 'H':

DestroyBiTree(T);

key = 0;

cout << "销毁成功!" << endl;

break;

}

}

}

}

}

int main()

{

BiTree T=NULL;

test(T);

}

按照测试函数逐个测试功能:

创建一颗二叉树如图:

遍历该二叉树

查找该二叉树的结点信息

在根节点插入右子树K,如图:

 最后测试清空和销毁功能:

哈夫曼编码的测试函数:

int main()

{

    HuffmanTree HT;

    HuffmanCode HC;

    cout << "请输入哈夫曼树的结点数目:";

    int n;

    cin >> n;

    cout << "请输入结点的值:" << endl;

    CreateHuffmanTree(HT, n);

    CreateHuffmanCode(HT, HC, n);

    cout << "进行哈夫曼编码:" << endl;

    for (int i = 1; i <= n; i++) {

        cout <<"第"<<i<<"个结点编码:" << HC[i] << endl;

    }

}

以(5,29 7,8,14,23,3,11)构造一颗哈夫曼树:

对应编码:

5: 0001

29:10

7: 1110

8: 1111

14:110

23:01

3: 0000

11:00

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值