二叉树的实现
二叉树的实现实验原理
二叉树的实现实验原理二叉树是一种常见的数据结构,它由节点组成,每个节点最多有两个子节点,通常称为左子节点和右子节点。
二叉树的实现原理如下:1. 节点的定义:每个节点包含一个值和两个指针,分别指向左子节点和右子节点。
节点可以使用类或结构体来表示,具体的实现方式取决于编程语言。
2. 树的定义:树由节点组成,其中一个节点被指定为根节点。
根节点没有父节点,其他节点都有且只有一个父节点。
每个节点最多有两个子节点,即左子节点和右子节点。
3. 添加节点:向二叉树中添加节点时,需要遵循以下规则:- 如果树为空,将节点作为根节点添加到树中。
- 如果节点的值小于当前节点的值,将节点添加为当前节点的左子节点。
- 如果节点的值大于等于当前节点的值,将节点添加为当前节点的右子节点。
4. 遍历树:遍历二叉树可以按照不同的顺序进行,常见的遍历方式有三种:- 前序遍历(Preorder Traversal):先访问根节点,然后按照前序遍历方式遍历左子树,最后按照前序遍历方式遍历右子树。
- 中序遍历(Inorder Traversal):先按照中序遍历方式遍历左子树,然后访问根节点,最后按照中序遍历方式遍历右子树。
- 后序遍历(Postorder Traversal):先按照后序遍历方式遍历左子树,然后按照后序遍历方式遍历右子树,最后访问根节点。
遍历树的过程可以使用递归或迭代的方式来实现,具体的实现方法取决于编程语言和使用的数据结构。
5. 删除节点:删除二叉树中的节点时,需要考虑多种情况。
如果要删除的节点是叶子节点,可以直接删除它。
如果要删除的节点只有一个子节点,可以将子节点移动到要删除的节点的位置。
如果要删除的节点有两个子节点,可以选择将其中一个子节点替代要删除的节点,或者选择左子树的最大节点或右子树的最小节点替代要删除的节点。
根据上述原理,可以使用类或结构体等数据结构和递归或迭代的方式来实现二叉树。
具体的实现方法和细节可能因编程语言而异,但以上原理是通用的。
二叉树的各种基本运算的实现实验报告
软件技术基础实验四--二叉树的各种基本运算的实现班级:电信0901学号:0703090106姓名:蒋玮珂实验四二叉树的各种基本运算的实现(1)实验题目:编写一个程序,实现二叉树的各种基本运算,并在此基础上设计一个主程序完成如下功能:(1)创建二叉树btree(2)求出二叉树btree的树高(3)中序遍历二叉树btree(4)统计二叉树btree的叶结点数(5)输出二叉树btree的所有叶结点(2)实验目的:(1)掌握二叉树的递归操作与运算;(2)加深对二叉树的建立,先序中序遍历方法以及树高的理解与应用(3)调试通过并正确执行给定功能要求的实验代码#include "stdafx.h"#include <fstream.h>struct bitree{char data;bitree *lchild;bitree *rchild;};bitree *createtree(char a[],char b[],int l1,int h1,int l2,int h2) {btree *root;int i,lhigh,rhigh;root=(btree*)malloc(sizeof(btree));root->data=a[l1];if(i=h1,(b[i]!=(root->data)),i++){lhigh=i-h1;rhigh=h2-i;if(lhigh)root->lchild=createtree(a,b,l1+1,l1+lhigh,h1,h1+lhigh-1);elseroot->lchild=NULL;if(rhigh)root->rchild=createtree(a,b,l2-rhigh+1,l2,h2-rhigh+1,h2);elseroot->rchild=NULL;}return root;}int treehigh(bitree *q)if(q==NULL)return 0;else{int lhigh,rhigh;lhigh=treehigh(q->lchild);rhigh=treehigh(q->rchild);if(lhigh>=rhigh)return lhigh+1;elsereturn rhigh+1;}}void inorder(bitree *q){j=0;if(q!=NULL){inorder(q->lchild,str1+(++j));*(str1+j)=q->data;inorder(q->rchild,str1+(++j));}}int countleaf(bitree *q, int count,int flag,char *str2) {k=0;if(q==0)return NULL;else if (q->lchild==NULL &&q->rchild==NULL){count ++;while (flag)*(str2+(k++))=q->data;return count;}else{countleaf(q->lchild ,count,flag,str2+(++k));countleaf(q->rchild ,count,flag,str2+(++k));if(!flag)return count;elsereturn NULL;}}void main()bitree *q;int high,flag,n=0,i=0;char x,y;ifstream infile("e:\\ProgramFiles\\MSDev98\\MyProjects\\jwk\\infile.txt");ofstream outfile("e:\\ProgramFiles\\MSDev98\\MyProjects\\jwk\\outfile.txt");char a[20],b[20],str2[20],str1[20];while(infile.get(x)){infile>>x;a[i++]=x;n++;}i=0;while(infile.get(y)){infile>>y;b[i++]=y;}q=createtree(a,b,1,n,1,n);high=treehigh(q);outfile<<"The height of the bitree is:"<<high<<endl;outfile<<"The sequence of the bitree by the way of inorder:"<<endl; inorder(q,str1);i=0;while(str1[i])outfile<<str1[i++];count=0;flag=0;count=countleaf(q,count,flag,str2);cout<<"The number of the leaves is:"<<endl<<count<<endl;flag=1;cout<<"The leaves of the bitree is:"<<endl;i=0;while(str2[i])outfile<<str2[i++];infile.close();outfile.close();}(4)实验结果截图。
实现二叉树的各种遍历算法实验报告
if(a[i]>kmax) kmax = a[i]; return kmax; } /** 求二叉树的节点个数 **/ int Nodes(BTNode *b) { if(b==NULL)
2.2:( 1 )实现二叉树的先序遍历 ( 2)实现二叉树的中序遍历 ( 3)实现二叉树的后序遍历
三 实验内容 :
3.1 树的抽象数据类型 : ADT Tree{
.专业 .整理 .
下载可编辑
数据对象 D: D 是具有相同特性的数据元素的集合 。 数据关系 R: 若 D 为空集 , 则称为空树 ;
若 D 仅含有一个数据元素 ,则 R 为空集 , 否则 R={H} , H 是如 下二元关系 :
if(b!=NULL) {
printf("%c",b->data); if(b->lchild!=NULL || b->rchild!=NULL) {
printf(" ("); DispBTNode(b->lchild); if(b->rchild != NULL)printf(" , "); DispBTNode(b->rchild); printf(" )"); } } } /** 深度 **/ int BTNodeDepth(BTNode *b)
下载可编辑
实现二叉树的各种遍历算法实验报告
一 实验题目 : 实现二叉树的各种遍历算法 二 实验要求 :
2.1:(1 ) 输出二叉树 b ( 2)输出 H 节点的左右孩子节点值 ( 3)输出二叉树 b 的深度 ( 4)输出二叉树 b 的宽度 ( 5)输出二叉树 b 的节点个数 ( 6)输出二叉树 b 的叶子节点个数 ( 7)释放二叉树 b
二叉树的储存结构的实现及应用
二叉树的储存结构的实现及应用二叉树是一种常见的数据结构,它在计算机科学和算法设计中广泛应用。
二叉树的储存结构有多种实现方式,包括顺序储存结构和链式储存结构。
本文将从这两种储存结构的实现和应用角度进行详细介绍,以便读者更好地理解二叉树的储存结构及其在实际应用中的作用。
一、顺序储存结构的实现及应用顺序储存结构是将二叉树的节点按照从上到下、从左到右的顺序依次存储在一维数组中。
通常采用数组来实现顺序储存结构,数组的下标和节点的位置之间存在一定的对应关系,通过数学计算可以快速找到节点的父节点、左孩子和右孩子。
顺序储存结构的实现相对简单,利用数组的特性可以迅速随机访问节点,适用于完全二叉树。
1.1 实现过程在采用顺序储存结构的实现中,需要首先确定二叉树的深度,然后根据深度确定数组的长度。
通过数学计算可以得到节点间的位置关系,初始化数组并按照规定的顺序将二叉树节点逐一填入数组中。
在访问二叉树节点时,可以通过计算得到节点的父节点和子节点的位置,从而实现随机访问。
1.2 应用场景顺序储存结构适用于完全二叉树的储存和遍历,常见的应用场景包括二叉堆和哈夫曼树。
二叉堆是一种特殊的二叉树,顺序储存结构可以方便地实现它的插入、删除和调整操作,因此在堆排序、优先队列等算法中得到广泛应用。
哈夫曼树则是数据压缩领域的重要应用,通过顺序储存结构可以有效地构建和处理哈夫曼树,实现压缩编码和解码操作。
二、链式储存结构的实现及应用链式储存结构是通过指针将二叉树的节点连接起来,形成一个类似链表的结构。
每个节点包含数据域和指针域,指针域指向节点的左右孩子节点。
链式储存结构的实现相对灵活,适用于任意形态的二叉树,但需要额外的指针空间来存储节点的地址信息。
2.1 实现过程在链式储存结构的实现中,每个节点需要定义为一个包含数据域和指针域的结构体或类。
通过指针来连接各个节点,形成一个二叉树的结构。
在树的遍历和操作中,可以通过指针的操作来实现节点的访问和处理,具有较高的灵活性和可扩展性。
c语言实现二叉树的四种遍历和求深度与叶子个数
c语言实现二叉树的四种遍历和求深度与叶子个数二叉树是一种常见的数据结构,它由节点组成,每个节点最多有两个子节点。
在C语言中,我们可以使用指针来实现二叉树的操作。
本文将介绍四种常见的二叉树遍历方式,以及如何求解二叉树的深度和叶子节点个数。
首先,我们需要定义一个二叉树节点的结构体,包含一个数据域和两个指针域,分别指向左子节点和右子节点。
代码如下:```cstruct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;};```接下来,我们可以实现二叉树的四种遍历方式:前序遍历、中序遍历、后序遍历和层序遍历。
前序遍历是指先访问根节点,然后递归地遍历左子树和右子树。
代码如下:```cvoid preorderTraversal(struct TreeNode* root) {if (root == NULL) {return;}printf("%d ", root->data);preorderTraversal(root->left);preorderTraversal(root->right);}```中序遍历是指先递归地遍历左子树,然后访问根节点,最后递归地遍历右子树。
代码如下:```cvoid inorderTraversal(struct TreeNode* root) {if (root == NULL) {return;}inorderTraversal(root->left);printf("%d ", root->data);inorderTraversal(root->right);}```后序遍历是指先递归地遍历左子树和右子树,最后访问根节点。
代码如下:```cvoid postorderTraversal(struct TreeNode* root) {if (root == NULL) {return;}postorderTraversal(root->left);postorderTraversal(root->right);printf("%d ", root->data);}```层序遍历是按照树的层次逐层遍历节点。
二叉排序树与平衡二叉树的实现
课程设计报告设计题目:二叉排序树与平衡二叉树的实现专业班级学生学号指导教师起止时间年学期目录1.需求分析: (3)1.1课程设计题目、任务及要求: (3)1.2课程设计思想: (3)2.概要设计: (5)2.1二叉排序树的定义: (5)2.2二叉排序的存储结构: (5)2.3模块划分: (5)2.4主函数流程图: (6)3.详细设计和代码: (8)3.1二叉链表: (8)3.2顺序表: (14)4.心得与体会: (18)1.需求分析:1.1课程设计题目、任务及要求:用二叉链表作存储结构:(1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序树T;(2)对二叉排序树T作中序遍历,输出结果;(3)计算二叉排序树T查找成功的平均查找长度,输出结果;(4)输入元素x,查找二叉排序树T,若存在含x的结点,则删除该结点,并作中序遍历(执行操作2);否则输出信息“无x”;用顺序表(一维数组)作存储结构:(1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序树T;(2)对二叉排序树T作中序遍历,输出结果;(3)计算二叉排序树T查找成功的平均查找长度,输出结果;(4)输入元素x,查找二叉排序树T:若存在含x的结点,则删除该结点,并作中序遍历(执行操作2);否则输出信息“无x”;1.2课程设计思想:生成二叉排序树:建立二叉排序树采用的是边查找边插入的方式。
查找函数采用递归的方式进行查找。
查找是按照二叉排序树的性质进行的,通过比较要插入元素的关键字与当前结点关键字的大小来决定我们是遍历当前结点的哪个子树。
如果小于当前结点关键字,则遍历它的左子树;大于当前结点关键字,则遍历它的右子树;等于当前关键字,则此元素不插入原树。
我们按照这样的规律,一直向下遍历,知道它的子树为空,则返回当前结点的上一个结点。
然后利用插入函数将该元素插入原树。
中序遍历:对二叉排序树进行中序遍历采用递归函数的方式。
二叉树的各种基本运算的实现实验报告
二叉树的各种基本运算的实现实验报告
一、实验目的
实验目的为了深入学习二叉树的各种基本运算,通过操作实现二叉树的建立、存储、查找、删除、遍历等各种基本运算操作。
二、实验内容
1、构造一个二叉树。
我们首先用一定的节点来构建一棵二叉树,包括节点的左子节点和右子节点。
2、实现查找二叉树中的节点。
在查找二叉树中的节点时,我们根据二叉树的特点,从根节点开始查找,根据要查找的节点的值与根节点的值的大小的关系,来决定接下来查找的方向,直到找到要查找的节点为止。
3、实现删除二叉树中的节点。
在删除二叉树节点时,我们要做的是找到要删除节点的父节点,然后让父节点的链接指向要删除节点的子节点,有可能要删除节点有一个子节点,有可能有两个极点,有可能没有子节点,我们要根据每种情况进行处理,来保持二叉树的结构不变。
4、对二叉树进行遍历操作。
二叉树的遍历有多种方法,本实验使用的是先序遍历。
首先从根节点出发,根据先序遍历的顺序,先访问左子树,然后再访问右子树,最后访问根节点。
三、实验步骤
1、构建二叉树:
我们用一个数组代表要构建的二叉树,第一项为根节点,第二项和第三项是根节点的子节点。
平衡二叉树的实现c语言
平衡二叉树的实现c语言平衡二叉树(AVL树)是一种自平衡的二叉查找树,其中任何节点的两个子树的高度差最多为1。
下面是一个简单的AVL树的C语言实现:```cinclude <>include <>typedef struct AVLNode {int key;int height;struct AVLNode left, right;} AVLNode;typedef struct {AVLNode root;} AVLTree;int getHeight(AVLNode node) {if (node == NULL)return 0;return node->height;}int getBalance(AVLNode node) {if (node == NULL)return 0;return getHeight(node->left) - getHeight(node->right);}AVLNode rotateRight(AVLNode y) {AVLNode x = y->left;AVLNode T2 = x->right;x->right = y;y->left = T2;y->height = max(getHeight(y->left), getHeight(y->right)) + 1; x->height = max(getHeight(x->left), getHeight(x->right)) + 1; return x; // new root is x}AVLNode rotateLeft(AVLNode x) {AVLNode y = x->right;AVLNode T2 = y->left;y->left = x;x->right = T2;x->height = max(getHeight(x->left), getHeight(x->right)) + 1; y->height = max(getHeight(y->left), getHeight(y->right)) + 1; return y; // new root is y}AVLNode insert(AVLTree tree, int key) {AVLNode root = tree->root;if (root == NULL) { // tree is empty, create a new node as root. tree->root = (AVLNode)malloc(sizeof(AVLNode));root = tree->root;root->key = key;root->height = 1;return root;} else if (key < root->key) { // insert into left subtree.root->left = insert(root->left, key);} else if (key > root->key) { // insert into right subtree.root->right = insert(root->right, key);} else { // duplicate keys not allowed.return root; // don't insert duplicate key.}root->height = 1 + max(getHeight(root->left), getHeight(root->right)); // adjust height of current node.int balance = getBalance(root);if (balance > 1 && key < root->left->key) { // left left case.return rotateRight(root); // rotate right.} else if (balance < -1 && key > root->right->key) { // right right case.return rotateLeft(root); // rotate left.} else if (balance > 1 && key > root->left->key) { // left right case. root->left = rotateLeft(root->left); // rotate left first.return rotateRight(root); // then rotate right.} else if (balance < -1 && key < root->right->key) { // right left case.root->right = rotateRight(root->right); // rotate right first.return rotateLeft(root); // then rotate left.} // keep balance.return root; // already balanced.} ```。
【数据结构】二叉树的实现
【数据结构】二叉树的实现//-------------------第一部分-----------------#include <stdio.h>typedef char TElemType;//建立结点typedef struct BiTree{TElemType data;struct BiTree *lchild,*rchild;}BiTree;//-------------------第二部分------------------//1、二叉树的建立:先序建立二叉树,//在创建完成二叉树之后,需要把根节点返回来,设置一个整型的临时变量//设置这个变量的目的就是为了返回根节点BiTree *CreateBiTree(BiTree *BT,int itemp){TElemType ch;BiTree *T1;//先申请一个节点T1 = (BiTree *)malloc(sizeof(BiTree));//如果失败,退出if(!T1)exit(1);//如果输入二叉树元素是“#”,说明这个元素是空的scanf("%c",&ch);if(ch !='#'){//将ch值存入新申请的节点中,新申请的节点,左右子树全为空T1->data = ch;T1->lchild = NULL;T1->rchild = NULL;//如果是根节点(只有一个),将申请的节点赋值给BTif(itemp == 0)BT = T1;//如果是左子树,将申请的节点赋值给BT的左孩子if(itemp == 1)BT->lchild = T1;//如果是右子树,将申请的节点赋值给BT的右孩子if(itemp == 2)BT->rchild = T1;//(2)创建左子树,整型变量为1,代表左子树CreateBiTree(T1,1);//(3)创建右子树,整型变量为2,代表右子树CreateBiTree(T1,2);}//返回根节点return BT;}//2、二叉树的遍历:三种方式:先序遍历、中序遍历、后序遍历//先序遍历口诀:根左右//中序遍历口诀:左根右//后续遍历口诀:左右根//(1)先序遍历二叉树void Pre_OrderTraverse(BiTree *T){//如果树存在if(T != NULL){//先输出根节点printf("%c ",T->data);//再输出左子树Pre_OrderTraverse(T->lchild);//最后输出右子树Pre_OrderTraverse(T->rchild);}}//(2)中序遍历二叉树void In_OrderTraverse(BiTree *T){//如果树存在if(T != NULL){//先遍历左子树In_OrderTraverse(T->lchild);//再输出根节点printf("%c ",T->data);//最后输出右子树In_OrderTraverse(T->rchild);}}//(3)后序遍历二叉树void Post_OrderTraverse(BiTree *T){//如果树存在if(T != NULL){//先输出左子树Post_OrderTraverse(T->lchild);//再输出右子树Post_OrderTraverse(T->rchild);//最后输出根节点printf("%c ",T->data);}}//-----------------------第三部分------------------------void main(){BiTree BT,*T;//1、以先序遍历的方式创建二叉树printf("先序建立二叉树,(每个结点为一个字符,空节点为“#”):\n");T = CreateBiTree(&BT,0);printf("-----------------------创建树成功!-------------------------\n");printf("\n");printf("\n");printf("\n");//2、以先序遍历的方式输出二叉树printf("先序建立二叉树的结果是:\n");Pre_OrderTraverse(T);printf("\n");printf("\n");printf("\n");//3、以中序遍历的方式输出二叉树printf("中序建立二叉树的结果是:\n");In_OrderTraverse(T);printf("\n");printf("\n");printf("\n");//4、以后序遍历的方式输出二叉树printf("后序建立二叉树的结果是:\n");Post_OrderTraverse(T);printf("\n");}。
平衡二叉树 实现方式
平衡二叉树实现方式平衡二叉树(BalancedBinaryTree)是一种特殊的二叉搜索树,它的左右子树深度差不超过1,因此可以避免在极端情况下二叉搜索树退化为链表的问题,从而保证了树的平衡性和查找效率。
实现平衡二叉树的方式有多种,常见的包括红黑树、AVL树、Treap 等。
其中,AVL树是一种最早提出的平衡二叉树,它的平衡条件更为严格,要求左右子树深度差不超过1,且左右子树都是AVL树。
而红黑树则是一种相对宽松的平衡二叉树,它的平衡条件是保证节点的黑色高度相等,且满足红黑色规则。
对于AVL树的实现,需要在插入和删除节点时进行旋转操作,以保证树的平衡。
具体而言,插入节点时,需要从插入节点的父节点开始,向上逐层检查左右子树深度差是否超过1,如果超过,则进行旋转操作,将不平衡子树变为平衡子树。
而删除节点时,则需要先找到要删除的节点,然后根据其子树的情况进行旋转操作,以保证删除后的树仍然是AVL树。
对于红黑树的实现,同样需要在插入和删除节点时进行旋转操作,以保证树的平衡。
不同之处在于,红黑树的旋转操作相对简单,且不需要进行平衡因子的计算。
具体而言,插入节点时,需要先将其插入为红色节点,然后进行着色和旋转操作,以保证红黑色规则不被破坏。
而删除节点时,则需要根据被删除节点的颜色和子树情况,进行着色和旋转操作,以保证删除后的树仍然满足红黑色规则。
除了AVL树和红黑树以外,还有一种名为Treap的平衡二叉树。
Treap是一种随机化平衡树,它的平衡性是通过随机建树来保证的。
具体而言,Treap会为每个节点赋予一个随机优先级,然后按照二叉搜索树的规则将节点插入到树中。
在插入节点时,如果节点的优先级高于其父节点,就进行旋转操作,以保证树的平衡。
相比于AVL树和红黑树,Treap的实现更加简单,且维护平衡的成本更低,但是由于其随机性,可能会出现树不平衡的情况。
二叉树的基本操作与实现实验报告
二叉树的基本操作与实现实验报告二叉树是一种重要的数据结构,在计算机科学领域中被广泛应用。
本实验将介绍二叉树的基本操作与实现,并给出相应的实验报告。
一、引言二叉树是一种特殊的树状结构,每个节点至多有两个子节点。
二叉树有许多重要的特性,如平衡二叉树、二叉树等,应用广泛。
在本实验中,我们将介绍二叉树的基本操作和实现。
二、实验目的1.掌握二叉树的基本概念和特性;2.熟悉二叉树的基本操作,包括创建、插入、删除、遍历等;3.学会使用编程语言实现二叉树的基本操作。
三、实验内容本实验主要包括以下内容:1.二叉树的定义和基本概念;2.二叉树的基本操作,包括创建、插入、删除、遍历等;3.使用编程语言实现二叉树的基本操作;4.测试和验证二叉树的基本操作的正确性。
四、实验步骤1.二叉树的定义和基本概念二叉树是一种树状结构,每个节点至多有两个子节点。
二叉树的每个节点包含一个数据项和指向左子树和右子树的指针。
二叉树的特性有很多,如完全二叉树、平衡二叉树、二叉树等。
2.二叉树的基本操作(1)创建二叉树:可以通过手动输入节点数据来创建二叉树,也可以通过读取文件中的数据来创建二叉树。
(2)插入节点:在指定位置插入一个新节点。
(3)删除节点:删除指定位置的节点。
(4)遍历二叉树:有前序遍历、中序遍历和后序遍历三种遍历方式。
3.使用编程语言实现二叉树的基本操作实现二叉树的基本操作可以使用编程语言来完成。
我们可以定义一个二叉树的结构体,包含节点数据和指向左右子树的指针。
然后根据具体的需求,实现相应的操作函数。
4.测试和验证二叉树的基本操作的正确性在完成二叉树的基本操作后,我们可以编写测试代码来验证操作的正确性。
通过创建二叉树,并进行插入、删除和遍历操作,观察输出结果是否符合预期。
五、实验结果与分析在完成二叉树的基本操作后,我们可以进行测试和验证。
通过输出二叉树的遍历结果,比对预期结果来判断操作是否正确。
同时,我们还可以观察二叉树的结构和特性,如是否满足平衡二叉树或二叉树的条件。
数据结构-二叉树类型的实现
实验4 表达式二叉树类型的实现源代码及每步注解:文件expression.h/*头文件以及存储结构*/#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<string.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW 0typedef int Status;/*二叉树结点类型*/typedef enum{INT,CHAR}ElemTag;/*INT为整型数据num,CHAR为字符型数据c*/ typedef struct TElemType{ElemTag tag;/*{INT,CHAR}指示是整型还是字符型*/union{int num;/*tag=INT时,为整型*/char c;/*tag=CHAR时,为字符型*/};} TElemType;/*二叉树的二叉链表存储表示 */typedef struct BiTNode{TElemType data;struct BiTNode *lchild,*rchild; /* 左右孩子指针 */}BiTNode,*BiTree;typedef BiTree SElemType;/*栈SqStack的元素*/typedef char SElemType1; /*栈SqStack1的元素*//*栈的顺序存储表示 */#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */#define STACKINCREMENT 2 /* 存储空间分配增量 *//*两个顺序栈*/typedef struct SqStack{SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */SElemType *top; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack; /* 顺序栈 */typedef struct SqStack1{SElemType1 *base; /* 在栈构造之前和销毁之后,base的值为NULL */SElemType1 *top; /* 栈顶指针 */int stacksize; /* 当前已分配的存储空间,以元素为单位 */}SqStack1; /* 顺序栈 *//*顺序栈的基本操作*/Status InitStack(SqStack *S){ /* 构造一个空栈S */(*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));if(!(*S).base)exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base;(*S).stacksize=STACK_INIT_SIZE;return OK;}Status StackEmpty(SqStack S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */if(S.top==S.base) return TRUE;else return FALSE;}Status Push(SqStack *S,SElemType e){ /* 插入元素e为新的栈顶元素 */if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */{(*S).base=(SElemType*)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));if(!(*S).base) exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base+(*S).stacksize;(*S).stacksize+=STACKINCREMENT;}*((*S).top)++=e;return OK;}Status Pop(SqStack *S,SElemType *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */ if((*S).top==(*S).base) return ERROR;*e=*--(*S).top;return OK;}Status GetTop(SqStack S,SElemType *e)if(S.top>S.base){*e=*(S.top-1);return OK;}elsereturn ERROR;}/*顺序栈的基本操作*/Status InitStack1(SqStack1 *S){ /* 构造一个空栈S */(*S).base=(SElemType1 *)malloc(STACK_INIT_SIZE*sizeof(SElemType1));if(!(*S).base)exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base;(*S).stacksize=STACK_INIT_SIZE;return OK;}Status StackEmpty1(SqStack1 S){ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */if(S.top==S.base) return TRUE;else return FALSE;}Status Push1(SqStack1 *S,SElemType1 e){ /* 插入元素e为新的栈顶元素 */if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */{(*S).base=(SElemType1*)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType1));if(!(*S).base) exit(OVERFLOW); /* 存储分配失败 */(*S).top=(*S).base+(*S).stacksize;(*S).stacksize+=STACKINCREMENT;}*((*S).top)++=e;return OK;}Status Pop1(SqStack1 *S,SElemType1 *e){ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */ if((*S).top==(*S).base) return ERROR;*e=*--(*S).top;return OK;}Status GetTop1(SqStack1 S,SElemType1 *e)if(S.top>S.base){*e=*(S.top-1);return OK;}elsereturn ERROR;}文件expression.cpp#include"expression.h"/*全局变量*/int save_number[31];/*在按原表达式输入形式中,输入的常量保存到数组save_number中,常量最多为30个,0单元不用*/char Expr_String[30];/*存放表达式的字符串*//*以字符序列的形式输入语法正确的前缀表达式,保存到字符串string*//*参数flag=0表示输出的提示信息是"请输入正确的前缀表示式:"*//*flag=1表示输出的提示信息为"请以表达式的原书写形式输入正确表示式:"*/Status Input_Expr(char *string,int flag){if(flag==0)printf("\n请输入正确的前缀表示式:");else printf("\n请以表达式的原书写形式输入正确表示式:");flushall();/*清理缓冲区*/gets(string);/*从键盘输入一串字符串作为表达式*/if(strlen(string)==1)/*输入的表达式字符串长度为1*/if(string[0]=='+'||string[0]=='-'||string[0]=='*'||string[0]=='/'||string[0 ]=='^')/*输入的表达式只有一个运算符*/{ printf("\n表达式只有一个字符,为运算符,错误!");return ERROR;} elseif((string[0]>='0'&&string[0]<'9')||(string[0]>='a'&&string[0]<='z')||(string[0 ]>='A'&&string[0]<='Z'))/*输入的表达式只有一个数字或字符*/{ printf("\n表达式只有一个字符!");return OK;}else {printf("\n输入的字符不是运算符也不是变量常量,错误!");return ERROR;}return OK;}/*判断字符string[i],如果是'0'-'9'常量之间,二叉树结点存为整型;否则,存为字符型*/void judge_value(BiTree *E,char *string,int i){if(string[i]>='0'&&string[i]<='9')/*为常量*/{(*E)->data.tag=INT;(*E)->data.num=string[i]-48;}else if(string[i]>=1&&string[i]<=20)/*为常量,常量存于数组save_number中*/{(*E)->data.tag=INT;(*E)->data.num=save_number[string[i]];} else/*为变量*/{(*E)->data.tag=CHAR;(*E)->data.c=string[i];}}/*以正确的前缀表示式并构造表达式E*/Status ReadExpr(BiTree *E,char *exprstring){SqStack S;int i,len;/*len为表达式的长度*/BiTree p,q;(*E)=(BiTree)malloc(sizeof(BiTNode));/*申请二叉树的根结点的空间*/(*E)->lchild=NULL;(*E)->rchild=NULL;len=strlen(exprstring);/*len赋值为表达式的长度*/if(len==1)/*表达式长度为1时,二叉树只有根结点*/judge_value(E,exprstring,0);/*将exprstring[0]存入二叉树的结点中*/ else{judge_value(E,exprstring,0);/*将exprstring[0]存入二叉树的结点中*/InitStack(&S);/*初始化栈*/q=(*E);Push(&S,q);/*入栈*/Push(&S,q);/*入栈,根结点入栈两次是为判断先序输入的表达式是不是正确的表达式*/for(i=1;i<len&&!StackEmpty(S);i++){p=(BiTree)malloc(sizeof(BiTNode));judge_value(&p,exprstring,i);/*将exprstring[i]存入二叉树的结点中*/p->lchild=NULL;p->rchild=NULL;if(exprstring[i]=='+'||exprstring[i]=='-'||exprstring[i]=='*'||exprstring[i ]=='/'||exprstring[i]=='^'){/*为运算符,运算符入栈,左孩子不空,向左孩子走,否则,如果右孩子不空,向右孩子走*/if(!q->lchild) {q->lchild=p;Push(&S,p);q=p;}else {q->rchild=p;Push(&S,p);q=p;}}else/*不是运算符,运算符出栈*/{if(!q->lchild) {q->lchild=p;Pop(&S,&q);}else {q->rchild=p;Pop(&S,&q);}}}if(StackEmpty(S)&&i>=len) return OK;/*栈空且i>=len,说明输入的表达式是正确的*/else /*输入的表达式是错误的*/{printf("\n输入的表达式有误!");return ERROR;}}}/*如果两个字符是运算符,比较两个运算符的优先级,c1比c2优先,返回OK,否则返回ERROR*/Status Pri_Compare(char c1,char c2){if((c1=='^'||c1=='*'||c1=='-'||c1=='+'||c1=='/')&&(c2=='^'||c2=='*'||c2=='-'||c2=='+'||c2=='/')){/*c1和c2为运算符*/if(c1=='^')/*c1为指数运算符,则当c2不为'^'时,c1比c2优先*/{if(c2!='^') return OK;else return ERROR;}else if(c1=='*'||c1=='/')/*c1为乘法或除法运算符,则当c2为'+'或'-',c1比c2优先*/{if(c2=='^'||c2=='*'||c2=='/') return ERROR;else return OK;}else return ERROR;/*其余,c1不比c2优先*/}else return ERROR;/*c1和c2不是运算符*/}/*用带括弧的中缀表达式输入表达式*/void WriteExpr(BiTree E){if(E)/*树不为空*/{ /*先递归左子树*/if(E->lchild&&E->lchild->data.tag==CHAR)/*E的左孩子不为空,且左孩子为字符*/{if(Pri_Compare(E->data.c,E->lchild->data.c))/*E->data.c比E->lchild->data.c优先*/{printf("(");WriteExpr(E->lchild);printf(")");}/*带括弧输出左子树*/else WriteExpr(E->lchild);/*否则,不带括弧输出左子树*/}else WriteExpr(E->lchild);/*否则,输出左子树*//*访问输出根结点的值*/if(E->data.tag==INT){printf("%d",E->data.num);}else printf("%c",E->data.c);/*后递归右子树*/if(E->rchild&&E->rchild->data.tag==CHAR)/*E的右孩子不为空,且右孩子为字符*/{if(Pri_Compare(E->data.c,E->rchild->data.c))/*E->data.c比E->rchild->data.c优先*/{printf("(");WriteExpr(E->rchild);printf(")");}/*带括弧输出右子树*/else WriteExpr(E->rchild);/*否则,不带括弧输出右子树*/}else WriteExpr(E->rchild);/*否则,输出右子树*/}}/*实现对表达式中的所有变量V的赋值(V=c),参数flag为表示是否赋值过的标志*/ void Assign(BiTree *E,char V,int c,int *flag){if(*E){if((*E)->data.tag==CHAR&&(*E)->data.c==V)/*如果找到要赋值的变量,赋值*/{(*E)->data.tag=INT;(*E)->data.num=c;*flag=1;}Assign(&((*E)->lchild),V,c,flag);/*递归左子树*/Assign(&((*E)->rchild),V,c,flag);/*递归左子树*/}}/*指数运算函数,底数为x,指数为exp*/long power(int x,int exp){long result;int i;for(i=1,result=1;i<=exp;i++)result*=x;return result;}/*运算符运算求值,参数opr1,opr2为常量,opr为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/long Operate(int opr1,char opr,int opr2){long result;switch(opr){case '+':/*加法*/result=opr1+opr2;return result;break;case '-':/*减法*/result=opr1-opr2;return result;break;case '*':/*乘法*/result=opr1*opr2;return result;break;case '/':/*除法,除法是在整型类型上的除法*/result=opr1/opr2;return result;break;case '^':/*指数运算*/result=power(opr1,opr2);return result;break;default:break;}}/*检查表达式是否还存在没有赋值的变量,以便求算数表达式的值*/Status Check(BiTree E){if(E&&E->data.tag==CHAR)/*树不为空*/{if(E->data.c!='*'&&E->data.c!='^'&&E->data.c!='-'&&E->data.c!='+'&&E->data. c!='/'){printf("\n表达式中仍存在变量没有赋值!没法求出表达式的值!");return ERROR;}/*存在变量,提示信息,后返回ERROR*/if(Check(E->lchild))/*递归左子树*/Check(E->rchild);/*递归右子树*/}}/*对算术表达式求值*/long Value(BiTree E){if(E)/*树不为空*/{if(!E->lchild&&!E->rchild&&E->data.tag==INT) return (E->data.num);/*结点的左孩子和右孩子为空,为叶子结点,返回结点的值*/return Operate(Value(E->lchild),E->data.c,Value(E->rchild));/*运算求值,后根遍历的次序对表达式求值,其中参数递归调用了Value()函数求左子树的值和右子树的值*/}}/*构造一个新的复合表达式*/void CompoundExpr(char P,BiTree *E1,BiTree E2){BiTree E;E=(BiTree)malloc(sizeof(BiTNode));/*申请一个结点存放运算符P*/E->data.tag=CHAR;E->data.c=P;/*申请到的结点值为P*/E->lchild=(*E1);/*结点的左孩子为E1*/E->rchild=E2;/*结点的右孩子为E2*/(*E1)=E;/*(*E1)为根结点*/printf("\n表达式E复合成功!其表达式变为:\n");WriteExpr(E);/*输出复合好的表达式*/}/*以表达式的原书写形式输入,表达式的原书写形式字符串string变为字符串pre_expr*//*后调用reversal_string()函数反转得到前缀表达式pre_expr*/Status Read_Inorder_Expr(char *string,char *pre_expr){int i,j,len,char_number=1;/*len表示字符串string的长度,char_number是记录数组save_number[]的个数*/int number;/*保存大于9的常量*/char c,c1;SqStack1 S;/*栈定义*/InitStack1(&S);/*初始栈*/Push1(&S,'#');/*先将字符'#'入栈,用来表示作为栈的最底一个元素*/len=strlen(string);/*len为字符串string的长度*/c=string[len-1];/*从字符串的最后一个字符开始向前扫描*/i=len-1;while(!StackEmpty1(S)&&i>=0)/*栈不为空且i大于等于0*/{if(c=='(')/*字符为'('*/{Pop1(&S,&c);/*出栈,赋值给c*/while(c!=')')/*假如c不为')',出栈*/{*pre_expr++=c;if(!StackEmpty1(S)&&GetTop1(S,&c1)&&c1!='#') Pop1(&S,&c);else {printf("\n输入的表达式有误!");return ERROR;}}}else if(c==')')/*字符为')',入栈*/{Push1(&S,c);}else if(c>='0'&&c<='9')/*字符为'0'-'9'之间,循环扫描string前一个字符,后确定常量的大小*/{number=c-48;/*number为第一个常量字符的ASCII码-48*/for(c1=string[i-1],j=1;(c1>='0'&&c1<='9')&&i>=0;j++,i--)/*循环扫描string前一个字符,求出常量后赋给number*/{number=(c1-48)*power(10,j)+number;/*number为扫描到的常量*/c1=string[i-2];}save_number[char_number]=number;/*将number存入到数组save_number中,下标为char_number*/*pre_expr++=char_number++;}else if((c>='a'&&c<='z')||(c>='A'&&c<='Z'))/*字符为'a'-'z'或'A'-'Z'之间的变量*/{/*string下一个字符不能为常量或变量,否则,出错*/if((string[i-1]>='0'&&string[i-1]<='9')||(string[i-1]>='A'&&string[i-1]<='Z ')||(string[i-1]>='a'&&string[i-1]<='z')){printf("\n输入的表达式有误!");return ERROR;}else *pre_expr++=c;}else if(c=='*'||c=='/')/*字符为运算符'*'或'/'*/{while(GetTop1(S,&c1)&&(c1=='^'))/*将c与栈顶的字符c1比较优先级*/{Pop1(&S,&c1);*pre_expr++=c1;}/*如果c1比c优先,出栈*/Push1(&S,c);/*入栈字符c*/}else if(c=='+'||c=='-')/*字符为运算符'+'或'-'*/{while(GetTop1(S,&c1)&&(c1=='^'||c1=='*'||c1=='/'))/*将c与栈顶的字符c1比较优先级*/{Pop1(&S,&c1);*pre_expr++=c1;}/*如果c1比c优先,出栈*/Push1(&S,c);/*入栈运算符c*/}else if(c=='^')/*字符为运算符'^'*/{Push1(&S,c);/*入栈运算符'^'*/}else {printf("\n输入的表达式有误!");return ERROR;}/*其他字符,错误,返回ERROR*/i--;/*下一个字符*/if(i>=0) c=string[i];/*i不小于0,c=string[i]循环下一个字符*/else /*否则,将清空栈*/while(!StackEmpty1(S)&&GetTop1(S,&c1)&&c1!='#'){Pop1(&S,&c);*pre_expr++=c;}}Pop1(&S,&c);/*将'#'出栈*/*pre_expr='\0';/*字符串结束符*/if(i<0&&StackEmpty1(S))return OK;else return ERROR;}/*将字符串exprstring反转过来*/void reversal_string(char *exprstring){int len,i,j;char temp;len=strlen(exprstring);/*len为exprstring的长度*/for(i=0,j=len-1;i<j;i++,j--)/*字符串前后两个字符对换*/{temp=exprstring[i];exprstring[i]=exprstring[j];exprstring[j]=temp;}}/*常数合并操作函数,合并表达式E中所有常数运算*/void MergeConst(BiTree *E){long result;if((*E)->lchild&&(*E)->rchild)/*左右孩子不为空*/{if((*E)->lchild->data.tag==INT&&(*E)->rchild->data.tag==INT)/*假如左右孩子为常量,合并*/{result=Operate((*E)->lchild->data.num,(*E)->data.c,(*E)->rchild->data.num); /*常数合并运算,调用Operate()函数求值*/(*E)->data.tag=INT;(*E)->data.num=result;/*修改之前的运算符为常量*/free((*E)->lchild);/*释放左孩子*/free((*E)->rchild);/*释放右孩子*/(*E)->lchild=(*E)->rchild=NULL;/*左右孩子置空*/}else{MergeConst(&((*E)->lchild));/*递归左孩子*/MergeConst(&((*E)->rchild));/*递归右孩子*/}}}/*主菜单*/char menu(){char choice;printf("\n\t****************************************");printf("\n\t K网络工程121班");printf("\n\t 学号:240121525 姓名:王云峰");printf("\n\t****************************************");printf("\n\t***********表达式类型的实现*************");printf("\n\t 1 >>>输入正确的前缀表达式");printf("\n\t 2 >>>带括弧的中缀表示式输出");printf("\n\t 3 >>>对变量进行赋值");printf("\n\t 4 >>>对算数表达式求值");printf("\n\t 5 >>>构造一个新的复合表达式");printf("\n\t 6 >>>以表达式的原书写形式输入");printf("\n\t 7 >>>合并表达式中所有常数运算");printf("\n\t 0 >>>退出");printf("\n\t****************************************");printf("\n\t请输入你的选择>>>>>");choice=getche();return choice;}/*主函数*/void main(){BiTree E,E1;/*两个表达式E和E1*/int flag=0;/*表达式E构造标志,为0表示未构造,为1表示已构造*/long result;/*保存算数表达式运算结果*/char V,P;int c;char string[30];while(1){ system("cls");switch(menu()){case '1':/*1 >>>输入正确的前缀表达式*/printf("\n\t*************************输入提示信息************************");printf("\n\t输入正确的前缀表达式的要求:");printf("\n\t\t【变量】 a-z或A-Z");printf("\n\t\t【常量】 0-9,不能超过9");printf("\n\t\t【运算符】 +,-,*,/,^(乘幂)");printf("\n\t请输入正确的前缀表达式,后按回车键存入缓冲区,否则可能会出错!");printf("\n\t*************************************************************") ;if(Input_Expr(Expr_String,0))if(ReadExpr(&E,Expr_String)){flag=1;printf("\n表达式构造成功!\n输入的带括弧的中缀表达式:");WriteExpr(E);}getch();break;case '2':/*2 >>>带括弧的中缀表示式输出*/printf("\n\t********************输出说明信息***********************************");printf("\n\t输出带括弧的中缀表达式:");printf("\n\t【1】如果表达式已经构造成功的,输出表达式;");printf("\n\t【2】如果表达式还未构造成功的,请返回主菜单选择构造表达式;");printf("\n\t【注】其中要注意的是,可能有一些表达式构造时没有办法判断为有误,");printf("\n\t 如果输出不是你想得到的,说明你之前输入的表达式有误,请重新构造!");printf("\n\t*************************************************************** *****");if(flag==1) {printf("\n带括弧的中缀表达式为:");WriteExpr(E);}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '3':/*3 >>>对变量进行赋值*/printf("\n\t********************赋值操作说明信息***********************************");printf("\n\t赋值操作:实现对表达式中的某一个变量V的赋值,即使V=C,C为一整数");printf("\n\t 【1】根据输出的表达式,输入要赋值的变量V,只能输入一个字符,否则出错");printf("\n\t 【2】输入要将变量V赋值为的整数C,只能是整数,否则出错");printf("\n\t 【注】如果表达式未构造,请回到主菜单选择构造表达式");printf("\n\t*************************************************************** ********");if(flag==1){int Assign_flag=0;printf("\n表达式E为:");WriteExpr(E);flushall();/*清理缓冲区*/printf("\n请输入要赋值的值:");V=getchar();printf("请输入要将赋值为:");scanf("%d",&c);Assign(&E,V,c,&Assign_flag);if(Assign_flag) {printf("\n赋值成功!\n赋值后的表达式为:");WriteExpr(E);}else printf("\n表达式里没有%c这个变量!",V);}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '4':/*4 >>>对算数表达式求值*/printf("\n\t********************算数表达式求值说明信息************************");printf("\n\t 【注】如果表达式还有变量未赋值,即表达式不是算数表达式");printf("\n\t 不能求出表达式的值,请回到主菜单选择赋值操作,后再求值");printf("\n\t*************************************************************** ***");if(flag==1){printf("\n算数表达式:");WriteExpr(E);if(Check(E)){result=Value(E);printf("\n求算数表达式的值:\t");WriteExpr(E);printf("=%ld",result);}}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '5':/*5 >>>构造一个新的复合表达式*/printf("\n\t*****************构造新的复合表达式说明信息***************************");printf("\n\t 【1】构造一个新的表达式E1,采用表达式的原书写形式输入");printf("\n\t 【2】构造表达式E1成功后,输入要复合表达式E 和E1的操作运算符(+,-,*,/,^)");printf("\n\t 【注】如表达式E未构造,不能复合表达式;如构造表达式E1错误,复合失败");printf("\n\t*************************************************************** ********");if(flag==1){printf("\n表达式E1为:");WriteExpr(E);printf("\n请构造新的表达式E2:");flushall();/*清理缓冲区*/if(Input_Expr(string,1)){if(Read_Inorder_Expr(string,Expr_String)){reversal_string(Expr_String);if(ReadExpr(&E1,Expr_String)){flag=1;printf("\n表达式E1构造成功!");WriteExpr(E1);printf("\n请输入要构造新的复合表达式的操作运算符>>>");P=getchar();while(P!='*'&&P!='/'&&P!='+'&&P!='-'&&P!='^'){flushall();/*清理缓冲区*/printf("\n输入的操作运算符有误!请重新输入>>>");P=getchar();}CompoundExpr(P,&E,E1);}else printf("\n复合新的表达式失败!请按任意键返回主菜单!");}}}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '6':/*6 >>>以表达式的原书写形式输入*/printf("\n\t*************以表达式的原书写形式输入说明信息************************");printf("\n\t输入正确的原书写形式表达式");printf("\n\t 【变量】 a-z或A-Z");printf("\n\t 【常量】大于等于0的正整数");printf("\n\t 【运算符】 +,-,*,/,^(乘幂)");printf("\n\t 【括弧】左括弧 ( ,右括弧 ) ");printf("\n\t 【注】表示式中常量最多只能是30个,超过30个,出错!");printf("\n\t按原书写形式输入中,请按照正确的方式输入,否则可能会出错!");printf("\n\t*************************************************************** *******");if(Input_Expr(string,1))if(Read_Inorder_Expr(string,Expr_String)){reversal_string(Expr_String);if(ReadExpr(&E,Expr_String)){flag=1;printf("\n表达式构造成功!\n输入的带括弧的中缀表达式:");WriteExpr(E);}}getch();break;case '7':/*7 >>>合并表达式中所有常数运算*/printf("\n***************合并表达式中的所有常数运算*******************************");printf("\n 【注】合并表达式中的所有常数运算并不能一次性将常数都合并!");printf("\n例如:表达式'1+2*(3+3*4+9/3)'的常数合并,选择7进行合并,结果变为\n'1+2*(3+12+3)',");printf("根据优先级先后合并的,如果要合并到最后,需多次选择7\n进行合并,又合并一次'1+2*(15+3)',");printf("再次合并'1+2*18',再次合并'1+36',\n再次合并'37',后无法合并!");printf("\n***************************************************************** *******");if(flag==1){printf("\n原表达式为:");WriteExpr(E);MergeConst(&E);printf("\n合并表达式中所有的常数运算后的表达式:");WriteExpr(E);}else printf("\n表达式未构造成功!请构造成功的表达式!");getch();break;case '0':/*0 >>>退出*/printf("\n请按任意键退出!");getch();exit(0);default :printf("\n输入有误!请按任意键回到主菜单重新选择!");getch();break;}}}。
java实现二叉树的基本操作
java实现二叉树的基本操作一、二叉树的定义树是计算机科学中的一种基本数据结构,表示以分层方式存储的数据集合。
树是由节点和边组成的,每个节点都有一个父节点和零个或多个子节点。
每个节点可以对应于一定数据,因此树也可以被视作提供快速查找的一种方式。
若树中每个节点最多只能有两个子节点,则被称为二叉树(Binary Tree)。
二叉树是一种递归定义的数据结构,它或者为空集,或者由一个根节点以及左右子树组成。
如果左子树非空,则左子树上所有节点的数值均小于或等于根节点的数值;如果右子树非空,则右子树上所有节点的数值均大于或等于根节点的数值;左右子树本身也分别是二叉树。
在计算机中实现二叉树,通常使用指针来表示节点之间的关系。
在Java中,定义一个二叉树节点类的代码如下:```public class BinaryTree {int key;BinaryTree left;BinaryTree right;public BinaryTree(int key) {this.key = key;}}```在这个类中,key字段表示该节点的数值;left和right字段分别表示这个节点的左右子节点。
1. 插入节点若要在二叉树中插入一个节点,首先需要遍历二叉树,找到一个位置使得插入新节点后,依然满足二叉树的定义。
插入节点的代码可以写成下面这个形式:```public void insert(int key) {BinaryTree node = new BinaryTree(key); if (root == null) {root = node;return;}BinaryTree temp = root;while (true) {if (key < temp.key) {if (temp.left == null) {temp.left = node;break;}temp = temp.left;} else {if (temp.right == null) {temp.right = node;break;}temp = temp.right;}}}```上面的代码首先创建了一个新的二叉树节点,然后判断二叉树根是否为空,若为空,则将这个节点作为根节点。
二叉树基本运算算法的实现
二叉树基本运算算法的实现
二叉树是一种常见的数据结构,基本运算算法包括二叉树的遍历、查找、插入、删除等操作。
下面是这些算法的实现:
1. 二叉树遍历:二叉树遍历有三种方式,分别是前序遍历、中序遍历和后序遍历。
其中,前序遍历先访问根节点,再访问左子树和右子树;中序遍历先访问左子树,再访问根节点和右子树;后序遍历先访问左子树,再访问右子树和根节点。
遍历可以使用递归算法或栈实现。
2. 二叉树查找:二叉树查找可以使用递归算法或循环算法实现。
递归算法通过比较节点值实现查找,如果查找值小于当前节点值,则在左子树中查找,否则在右子树中查找。
循环算法使用二叉树的特性,比较查找值和当前节点值的大小,根据大小关系不断移动到左子树或右子树中进行查找,直到找到目标节点或遍历到叶子节点为止。
3. 二叉树插入:二叉树插入需要先查找到插入位置,然后在该位置插入一个新节点。
插入操作可以使用递归算法或循环算法实现。
4. 二叉树删除:二叉树删除分为三种情况:删除叶子节点、删除只有一个孩子的节点和删除有两个孩子的节点。
删除叶子节点很简单,只需要将其父节点的指针设为NULL即可。
删除只有一个孩子的节点需要将父节点的指针指向该节点的
孩子节点。
删除有两个孩子的节点需要找到该节点的后继节点(或前驱节点),将后继节点的值复制到该节点中,然后删除后继节点。
上述算法的实现需要根据具体的编程语言进行调整和实现。
二叉树实现及应用实验报告
二叉树实现及应用实验报告实验名称:二叉树实现及应用实验目的:1. 实现二叉树的创建、插入和删除操作。
2. 学习二叉树的遍历方法,并能够应用于实际问题。
3. 掌握二叉树在数据结构和算法中的一些常用应用。
实验内容:1. 实现二叉树的创建、插入和删除操作,包括二叉树的构造函数、插入函数和删除函数。
2. 学习二叉树的三种遍历方法:前序遍历、中序遍历和后序遍历,并应用于实际问题。
3. 掌握二叉树的一些常用应用,如二叉搜索树、平衡二叉树和哈夫曼树等。
实验步骤:1. 创建二叉树的结构体,包括树节点和树的根节点。
2. 实现二叉树的构造函数,用于创建二叉树的根节点。
3. 实现二叉树的插入函数,用于将元素插入到二叉树中的合适位置。
4. 实现二叉树的删除函数,用于删除二叉树中的指定元素。
5. 学习并实现二叉树的前序遍历、中序遍历和后序遍历函数。
6. 运用二叉树的遍历方法解决实际问题,如查找二叉树中的最大值和最小值。
7. 学习并应用二叉搜索树、平衡二叉树和哈夫曼树等常用二叉树结构。
实验结果:1. 成功创建、插入和删除二叉树中的元素,实现了二叉树的基本操作。
2. 正确实现了二叉树的前序遍历、中序遍历和后序遍历,并能够正确输出遍历结果。
3. 通过二叉树的遍历方法成功解决了实际问题,如查找二叉树中的最大值和最小值。
4. 学习并熟练应用了二叉搜索树、平衡二叉树和哈夫曼树等常用二叉树结构,丰富了对二叉树的理解。
实验分析:1. 二叉树是一种重要的数据结构,具有较好的数据存储和查找性能,广泛应用于计算机科学和算法领域。
2. 通过实验,我们深入了解了二叉树的创建、插入和删除操作,以及前序遍历、中序遍历和后序遍历的原理和应用。
3. 实际问题往往可以转化为二叉树的遍历问题进行求解,通过实验,我们成功应用了二叉树的遍历方法解决了实际问题。
4. 熟练掌握二叉搜索树、平衡二叉树和哈夫曼树的原理和应用,对于提高我们在数据结构和算法方面的设计能力具有重要意义。
实现二叉树的各种基本运算的算法代码
实现二叉树的各种基本运算的算法代码(一)创建二叉树1. 二叉树的链表存储结构://定义二叉树的链表存储结构typedef struct BiTNode{char data;struct BiTNode *lchild, *rchild;} BiTNode, *BiTree;2.利用二叉树的链表存储结构,创建一棵二叉树//根据二叉树的链表存储结构,创建一棵二叉树BiTree CreateBiTree(BiTree T){char c;scanf(&c);if(c=='#')T=NULL;else{T=(BiTree)malloc(sizeof(BiTNode)); // 产生根节点 T->data=c; // 生成根结点T->lchild = CreateBiTree(T->lchild); // 构造左子树 T->rchild = CreateBiTree(T->rchild); // 构造右子树 }return T;}(二)二叉树的遍历1.先序遍历// 先序遍历:根左右void PreOrderTraverse(BiTree T){if(T==NULL)return;printf('%c',T->data); // 访问根结点PreOrderTraverse(T->lchild); // 遍历左子树PreOrderTraverse(T->rchild); // 遍历右子树}2.中序遍历// 中序遍历:左根右void InOrderTraverse(BiTree T){if(T==NULL)return;InOrderTraverse(T->lchild); // 遍历左子树 printf('%c',T->data); // 访问根结点InOrderTraverse(T->rchild); // 遍历右子树 }3.后序遍历// 后序遍历:左右根void PostOrderTraverse(BiTree T){if(T==NULL)return;PostOrderTraverse(T->lchild); // 遍历左子树 PostOrderTraverse(T->rchild); // 遍历右子树 printf('%c',T->data); // 访问根结点}(三)二叉树的其他基本运算1.计算二叉树的结点数// 计算二叉树的结点数int CountTreeNode(BiTree T){if(T==NULL)return 0; // 二叉树T为空时,结点数为0elsereturnCountTreeNode(T->lchild)+CountTreeNode(T->rchild)+1; }2.计算二叉树的深度// 计算二叉树的深度int TreeDepth(BiTree T){int depL, depR;if(T==NULL)return 0; // 二叉树T为空时,深度为0else{depL = TreeDepth(T->lchild); // 左子树深度depR = TreeDepth(T->rchild); // 右子树深度if(depL > depR)return depL+1;elsereturn depR+1;}}。
实验五 二叉树基本操作的编程实现
实验五二叉树基本操作的编程实现【实验目的】内容:二叉树基本操作的编程实现要求:二叉树基本操作的编程实现(2学时,验证型),掌握二叉树的建立、遍历、插入、删除等基本操作的编程实现,也可以进一步编程实现查找等操作,存储结构主要采用顺序或链接结构。
也鼓励学生利用基本操作进行一些应用的程序设计。
【实验性质】验证性实验(学时数:2H)【实验内容】以下的选题都可以作为本次实验的推荐题目1.建立二叉树,并以前序遍历的方式将结点内容输出。
2.将一个表示二叉树的数组结构转换成链表结构。
3.将表达式二叉树方式存入数组,以递归方式建立表达式之二叉树状结构,再分别输出前序、中序及后序遍历结果,并计算出表达式之结果。
【思考问题】1.二叉树是树吗?它的定义为什么是递归的?2.三种根序遍历主要思路是什么?3.如果不用遍历算法一般启用什么数据结构实现后序遍历?4.举出二叉树的应用范例?【参考代码】(一)建立二叉树,并以前序遍历的方式将结点内容输出*//*===============================================*//*程序构思:*//*输入元素值后建立二叉树,以递归的方式做前序遍历,*//*其顺序为:结点-左子-右子树,并将二叉树结点内容输出。
*/#include<stdlib.h>#include<stdio.h>struct tree /*声明树的结构*/{struct tree *left; /*存放左子树的指针*/int data; /*存放结点数据内容*/struct tree *right; /*存放右子树的指针*/};typedef struct tree treenode; /*声明新类型树结构*/typedef treenode *b_tree; /*声明二叉树的链表*//*===============================================*//*插入二叉树结点*//*===============================================*/b_tree insert_node (b_tree root, int node){b_tree newnode; /*声明树根指针*/b_tree currentnode; /*声明目前结点指针*/b_tree parentnode; /*声明父结点指针*//*建立新结点的内存空间*/newnode=(b_tree )malloc (sizeof(treenode));newnode->data=node; /*存入结点内容*/ newnode->right=NULL; /*设置右指针初值*/ newnode->left=NULL; /*设置左指针初值*/if (root==NULL)return newnode; /*返回新结点的位置*/ else{currentnode=root; /*存储目前结点指针*/while (currentnode!=NULL){parentnode=currentnode; /*存储父结点指针*/if (currentnode->data>node) /*比较结点的数值大小*/currentnode=currentnode->left; /*左子树*/elsecurrentnode=currentnode->right; /*右子树*/ }if (parentnode->data>node) /*将父结点和子结点做连结*/ parentnode->left=newnode; /*子结点为父结点之左子树*/ elseparentnode->right=newnode; /*子结点为父结点之右子树*/ }return root; /*返回根结点之指针*/ }/*===============================================*//*建立二叉树*//*===============================================*/b_tree create_btree (int *data, int len){b_tree root=NULL; /*根结点指针*/ int i;for (i=0; i<len; i++) /*建立树状结构*/ root=insert_node(root, );return root;}/*===============================================*//*二叉树前序遍历*//*===============================================*/void preorder (b_tree point){if (point!=NULL) /*遍历的终止条件*/ {printf ("%2d", point->data); /*处理打印结点内容*/preorder (point->left); /*处理左子树*//*处理右子树*/}}/*==================================================*//*主程序:建立二叉树,并以前序遍历输出二叉树结点内容*//*==================================================*/void main(){b_tree root=NULL; /*树根指针*/int i, index;int value; /*读入输入值所使用的暂存变量*/ int nodelist[20]; /*声明存储输入数据之数组*/printf ("\n Please input the elements of binary tree(Exit for 0): \n");index=0;/*------------------读取数值存到数组中------------------*/scanf ("%d", &value); /*读取输入值存到变量value*/while (value!=0){nodelist[index]=value;;scanf ("%d", &value);}/*----------------------建立二叉树----------------------*/root=create_btree(nodelist, index);/*--------------------前序遍历二叉树--------------------*/printf ("\n The preorder traversal result is (");preorder( );printf (") \n");}/*希望的结果*/ /*Please input the elements of binary tree(Exit for 0): *//*6 3 1 9 5 7 4 8 0 *//* */ /*The preorder traversal result is (6 3 1 5 4 9 7 8) */(二)将一个表示二叉树的数组结构转换成链表结构/*===============================================*//*程序构思:*//*给定一个二叉树数组结构,使用递归方式建立一棵二叉树,*//*并中序遍历的方式输出二叉树结点内容。
二叉树的完整代码实现
⼆叉树的完整代码实现1 #include<stdio.h>2 #include<stdlib.h>3 #include<malloc.h>45 typedef struct Node//结构体6 {7char data;8struct Node *LChild;9struct Node *RChild;10 } BinNode,*BinTree;1112 BinTree CreateTree(BinTree T)13 {14char ch;15 scanf("%c",&ch);16if(ch=='#')17return NULL;18else19 {20 T=(BinTree)malloc(sizeof(BinNode));21 T->data=ch;22 T->LChild=CreateTree(T->LChild);/*创建左⼦树*/23 T->RChild=CreateTree(T->RChild);/*创建右⼦树*/24return T;25 }26 }2728void PreOrder(BinTree root)//先序遍历29 {30if (root != NULL)31 {32 printf("%c", root->data);33 PreOrder(root->LChild);34 PreOrder(root->RChild);35 }36 }3738void InOrder(BinTree root)//中序遍历39 {40if (root != NULL)41 {42 InOrder(root->LChild);43 printf("%c", root->data);44 InOrder(root->RChild);45 }46 }4748void PostOrder(BinTree root)//后序遍历49 {50if (root != NULL)51 {52 PostOrder(root->LChild);53 PostOrder(root->RChild);54 printf("%c", root->data);55 }56 }57/*求⼆叉树结点总数*/58int Count(BinTree T)59 {60if(T==NULL)61return0; /*空⼆叉树结点数为0*/62else/*左右⼦树结点总数加1*/63return Count(T->LChild)+Count(T->RChild)+1;64 }65//叶⼦数66int LeafCount(BinTree T){67if(T == NULL){68return0;69 }70else if ((T->LChild==NULL) && (T->RChild==NULL)){71return1;72 }73else{74return LeafCount(T->LChild)+LeafCount(T->RChild);75 }76 }77int main()78 {7980 BinTree bt;81 printf("⼀、请按先序的⽅式输⼊⼆叉树的结点元素(注:输⼊#表⽰节点为空)如:ABC##DE#G##F###\n");82 bt=CreateTree(bt);83 printf("⼆、前序遍历⼆叉树:\n");84 PreOrder(bt);85 printf("\n");86 printf("三、中序遍历⼆叉树:\n");87 InOrder(bt);88 printf("\n");89 printf("四、后序遍历⼆叉树:\n");90 PostOrder(bt);91 printf("\n");92 printf("五、⼆叉树结点数: %d\n",Count(bt));93 printf("六、叶⼦节点的个数:%d \n",LeafCount(bt));94 system("pause");95 }。
c语言实现二叉树各种基本运算的算法
c语言实现二叉树各种基本运算的算法二叉树是一种常见的数据结构,可以应用于许多算法和问题中。
在C语言中,我们可以使用指针和结构体来实现二叉树的各种基本运算。
本文将详细介绍二叉树的创建、插入、删除、查找以及遍历等基本操作的算法。
1.创建二叉树创建二叉树可以通过递归的方式来实现。
首先定义一个表示二叉树节点的结构体,包含一个值和左右子节点指针。
然后,通过递归地创建左右子树来构建整个二叉树。
```ctypedef struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;} TreeNode;//创建二叉树TreeNode* createBinaryTree() {int data;scanf("%d", &data);if (data == -1) { // -1表示空节点return NULL;}TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); node->data = data;node->left = createBinaryTree();node->right = createBinaryTree();return node;}```2.插入节点在二叉树中插入节点可以按照二叉搜索树的性质进行。
如果要插入的值小于当前节点的值,则将其插入到左子树中,否则插入到右子树中。
如果子树为空,则直接创建一个新节点作为子树。
```c//插入节点TreeNode* insertNode(TreeNode* root, int data) {if (root == NULL) {TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));newNode->data = data;newNode->left = NULL;newNode->right = NULL;return newNode;}if (data < root->data) {root->left = insertNode(root->left, data);} else {root->right = insertNode(root->right, data);}return root;}```3.删除节点删除二叉树中的节点可以分为三种情况:删除叶子节点、删除只有一个子节点的节点、删除有两个子节点的节点。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if(current!=NULL)
{
cout<<current->element<<" ";
PreOrder(current->leftchild());
PreOrder(current->rightchild());
}
}
/////////中序遍历
void BinaryTree::InOrder(BinaryTreeNode *current)const
if(ch=='@')
*current=NULL;//current=NULL;
else{
current1=new BinaryTreeNode(ch);
if(root==NULL)
root=current1;
* current=current1;
//////统计叶结点个数
void CountLeaf(BinaryTreeNode * root,int &);
int BtDepth(BinaryTreeNode *root)const;
};
///////////////////////////////////////
///判断是否为空树
{
BinaryTreeNode *temp;
if(root=NULL)
return NULL;
if((root->leftchild()==current)||(root->rightchild()==current))
return root;
if((temp=GetParent(root->leftchild(),current))!=NULL)
void InOrder(BinaryTreeNode *root)const;
///////后序遍历
void PostOrder(BinaryTreeNode *root)const;
//////层序遍历
void LevelOrder(BinaryTreeNode *root)const;
////////////////////////////////////////
//二叉树的结点类
class BinaryTreeNode{
friend class BinaryTree;
private:
char element;
BinaryTreeNode *left;
BinaryTreeNode *right;
int x=0;
BT.CountLeaf(BT.Root(),x);
cout<<x<<endl;
}
//二叉树类的定义
class BinaryTree{
private:
BinaryTreeNode * root;
BinaryTreeNode *GetParent(BinaryTreeNode *root,BinaryTreeNode *current);
public:
////////
bool BinaryTree::isEmpty()const
{
return((root)?true:falseபைடு நூலகம்;
}
///////////////////////////
/////////////////////////////取父结点
BinaryTreeNode * BinaryTree::GetParent(BinaryTreeNode *root,BinaryTreeNode *current)
{
if(root!=NULL)
{
if((root->leftchild()==NULL)&&(root->rightchild()==NULL))
count++;
CountLeaf(root->leftchild(),count);
CountLeaf(root->rightchild(),count);
{//采用前序遍历的方法建立一棵树,传递的参数为一个指向结点的指针的指针,目的是为了解决传值的问题
//输入@符号的时候,表示一棵子树结束
BinaryTreeNode *current1;
char ch;
cout<<"Please input the element:";
cin>>ch;
void DeleteBinaryTree(BinaryTreeNode *root);
/////////////////////////
~BinaryTree()
{DeleteBinaryTree(root);}
//////////////////////////析构函数
BinaryTreeNode * Root(){return root;}//取根结点的值
二叉树的实现.txt32因为爱心,流浪的人们才能重返家园;因为爱心,疲惫的灵魂才能活力如初。渴望爱心,如同星光渴望彼此辉映;渴望爱心,如同世纪之歌渴望永远被唱下去。#include<iostream>
#include<queue>
using namespace std;
#define NULL 0
{
if(root)
{
DeleteBinaryTree(root->left);
DeleteBinaryTree(root->right);
delete root;
}
}
////////////////////////////////
//创建一棵二叉树
void BinaryTree::BuildTree(BinaryTreeNode **current)
{
if((current==NULL)||(current==root))
return NULL;
return GetParent(root,current);
}
/////////////////////////////////////////////
//删除树
void BinaryTree::DeleteBinaryTree(BinaryTreeNode *root)
aQueue.push(pointer);
while(!aQueue.empty())
{
pointer=aQueue.front();
cout<<pointer->element<<" ";
aQueue.pop();
if(pointer->leftchild())
BinaryTreeNode ** Root1(){return &root;}//取根结点的地址值,主要是为建立树的时候使用
void CreateTree(const char & elem,BinaryTree &leftTree,BinaryTree & rightTree);
bool isEmpty()const;
//////层序遍历
void BinaryTree::LevelOrder(BinaryTreeNode *current)const
{
queue<BinaryTreeNode *>aQueue;
BinaryTreeNode *pointer=current;
if(pointer)
BinaryTreeNode *Parent(BinaryTreeNode * current);
void BuildTree(BinaryTreeNode **root);
////////前序访问
void PreOrder(BinaryTreeNode *root)const;
///////中序遍历
return temp;
else return GetParent(root->rightchild(),current);
}
////////////////////////////////////////////////
/////
BinaryTreeNode * BinaryTree::Parent(BinaryTreeNode * current)
BuildTree(&((*current)->left));
BuildTree(&((*current)->right));
}
}
/////////////////////////////////////////////定义结束
//前序访问
void BinaryTree::PreOrder(BinaryTreeNode *current)const
public:
BinaryTreeNode();
BinaryTreeNode(const char &ele,BinaryTreeNode * l=NULL,BinaryTreeNode *r=NULL)
{
element=ele;
left=l;
right=r;
}
aQueue.push(pointer->leftchild());
if(pointer->rightchild())