大二学生的 C++数据结构 有部分Openjudge提交的代码没有删除
邮箱:liu_772021@yeah.net
欢迎交流讨论~
有用的话,点赞留言就可以表示感谢啦
//
// main.cpp
// Tree and BiTree
//
// Created by Liu_77 on 2021/12/24.
//
#include <iostream>
using namespace std;
#define MAXSIZE 1000
typedef char ElemType;
//二叉树的链式存储结构结点声明
typedef struct tnode{
ElemType data;
tnode *lchild,*rchild;
}BTNode;
//二叉树的顺序存储结构的类型声明
typedef ElemType SqBinTree[MAXSIZE];
//为方便运算,通常将下标为0的位置空着,值为‘#’的结点为空结点
//对于一个下标为i的结点,如果有双亲,其双亲结点的下标为i/2;如果他有左孩子,下标为2i;如果有右孩子,下标为2i+1
//---------------------------括号法创建一个二叉树------------------------------
//算法中使用一个栈St[]保存有孩子结点的结点地址,这里直接采用数组St[]存放栈中元素
void CreateBTree(BTNode *&bt,char *str){
BTNode *St[MAXSIZE],*p = NULL;
//int型top变量做栈顶指针。
int top = -1,k = 0,j = 0;
char ch;
//建立的二叉树初始为空
bt = NULL;
ch = str[j];
//str未扫描完时,循环:
while(ch != '\0'){
switch(ch){
//处理左孩子结点,标记值k设置为1,表示其后创建的结点讲作为这个结点的左孩子结点。
case'(':
{
//将前面刚创建的双亲结点进栈;
top++; St[top] = p; k = 1; break;
}
//处理右孩子结点,标记值k设置为2,表示其后创建的结点为右孩子结点
case',':
{
k = 2; break;
}
//表示栈中结点的左右孩子结点处理完毕,退栈。
case ')':
{
top--; break;
}
//其他情况,表示要创建一个结点,根据标记值k建立它与栈顶结点之间的联系。
default:
{
//创建新二叉树结点
p = (BTNode *)malloc(sizeof(BTNode));
p->data = ch;
p->lchild = p->rchild = NULL;
//如果二叉树为空,p为跟结点。
if(bt == NULL){
bt = p;
}
//二叉树不为空:
else{
switch(k){
//k == 1,该结点是栈顶结点的左孩子
case 1:
{
St[top]->lchild = p; break;
}
//k == 2,该结点是栈顶结点的右孩子
case 2:
{
St[top]->rchild = p; break;
}
}
}
}
}
//处理ch数组中下一位元素
j++;
ch = str[j];
}
}
//销毁二叉树bt的运算算法
//递归模型如下:
//f(bt) = 不做任何事 当bt == NULL
//f(bt) = f(bt->lchild);f(bt->rchild);free(bt) 当 其他情况
void DestroyBTree(BTNode *&bt){
//当bt == NULL
//不做任何事情
//当 其他情况
if(bt != NULL){
//1当前结点左右孩子结点递归调用;
DestroyBTree(bt->lchild);
DestroyBTree(bt->rchild);
//2释放当前结点
free(bt);
}
}
//f(bt)---大问题,释放二叉树bt的全部结点空间;
//f(bt->lchild)和f(bt->rchild)---小问题,分别释放bt的左右子树的全部结点空间;
//求二叉树高度运算算法
//递归模型如下:
//f(bt) = 0 当bt == NULL
//f(bt) = MAX{f(bt->lchild),f(bt->rchild)} + 1 当 其他情况
int BTHeigh(BTNode *bt){
int lchilddep,rchilddep;
//空(子)树,返回0
if(bt == NULL){
return 0;
}
else{
//求左子树的高度为lchilddep
lchilddep = BTHeigh(bt->lchild);
//求右子树的高度为rchilddep
rchilddep = BTHeigh(bt->rchild);
//返回当前最大高度 + 1作为当前结点子树的高度
return (lchilddep > rchilddep) ? (lchilddep + 1) : (rchilddep + 1);
}
}
//求二叉树结点个数
//递归模型如下:
//f(bt) = 0 当bt == NULL
//f(bt) = f(bt->lchild) + f(bt->rchild) + 1 当 其他情况
int NodeCount(BTNode *bt){
int num1,num2;
//当bt == NULL,空树时返回0
if(bt == NULL){
return 0;
}
//当 其他情况
//当前结点左右孩子结点递归调用,返回左右孩子结点做跟结点的子树的全部结点数,再加上他们的双亲结点本身的1
else{
//求左子树结点个数
num1 = NodeCount(bt->lchild);
//求右子树结点个数
num2 = NodeCount(bt->rchild);
return (num1 + num2 + 1);
}
}
//求二叉树叶子结点个数运算算法
//递归模型如下:
//f(bt) = 0 当bt == NULL
//f(bt) = 1 当bt == 叶子结点
//f(bt) = f(bt->lchild) + f(bt->rchild) 当 其他情况
int LeafCount(BTNode *bt){
int num1,num2;
//空树返回0
if(bt == NULL){
return 0;
}
//叶子结点,返回1
else if(bt->lchild == NULL && bt->rchild == NULL){
return 1;
}
//非空非叶子结点,返回左子树叶子结点数+右子树叶子结点数
else{
num1 = LeafCount(bt->lchild);
num2 = LeafCount(bt->rchild);
return (num1 + num2);
}
}
//以括号表示法输出二叉树运算算法
//过程:先输出跟结点值;当存在左孩子或右孩子结点时输出‘(’,然后递归处理左子树;再输出‘,’,递归处理右子树,最后输出一个')'
void DispBTree(BTNode *bt){
if(bt != NULL){
printf("%c",bt->data);
if(bt->lchild != NULL || bt->rchild != NULL){
printf("(");
DispBTree(bt->lchild);
if(bt->rchild != NULL){
printf(",");
}
DispBTree(bt->rchild);
printf(")");
}
}
}
//----------------------------二叉树遍历------------------------------
//先序遍历
//若二叉树非空,则:
/*
1)访问根结点
2)先序遍历左子树;
3)先序遍历右子树
*/
void PreOrder(BTNode *bt){
if(bt != NULL){
printf("%c ",bt->data);
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
//中序遍历
//若二叉树非空,则:
/*
1)中序遍历左子树
2)访问根结点
3)中序遍历右子树
*/
void InOrder(BTNode *bt){
if(bt != NULL){
InOrder(bt->lchild);
printf("%d ",bt->data);
InOrder(bt->rchild);
}
}
//后序遍历
//若二叉树非空,则:
/*
1)后序遍历左子树
2)后序遍历右子树
3)访问根结点
*/
void PostOrder(BTNode *bt){
if(bt != NULL){
PostOrder(bt->lchild);
PostOrder(bt->rchild);
printf("%d ",bt->data);
}
}
//层次遍历算法
//按照从上向下,同一层从左向右的次序访问所有结点;采用一个【循环队列】qu实现
//实现:
/*
1)先将跟结点进队;
2)若队不空,出队一个结点p,访问它;
3)若有左孩子,则左孩子结点进队;若有右孩子,右孩子结点进队
4)重复1)2)3),直到队空为止
*/
//循环队列的实现:直接采用数组qu存放队中元素,另用两个int变量front和rear分别做对头指针和队尾指针;
void LevelPost(BTNode *bt){
BTNode *p;
//定义循环队列,存放二叉链结点指针
BTNode *qu[MAXSIZE];
//定义对头指针和队尾指针
int front,rear;
//置队列为空队列
front = rear = 0;
//跟结点指针进队
rear++;
qu[rear] = bt;
//当队不空,循环
while(front != rear){
//出队结点p;
front = (front + 1) % MAXSIZE;
p = qu[rear];
//访问该结点
printf("%c ",p->data);
//如果有左孩子,进队
if(p->lchild != NULL){
rear = (rear + 1) % MAXSIZE;
qu[rear] = p->lchild;
}
//如果有右孩子,进队
if(p->lchild != NULL){
rear = (rear + 1) % MAXSIZE;
qu[rear] = p->rchild;
}
}
}
//-----------------遍历算法的应用----------------------
//1-求单分枝结点个数
//采用后序遍历方式求解,先求左子树中单分支结点个数m,再求出右子树中单分支结点个数n;若跟结点为单位直接点,返回m+n+1;否则返回m+n;
int onenodes1(BTNode *bt){
int m,n;
if(bt != NULL){
m = onenodes1(bt->lchild);
n = onenodes1(bt->rchild);
//单分枝结点情况
if((bt->lchild == NULL && bt->rchild != NULL) || (bt->lchild != NULL && bt->rchild == NULL)){
return (1 + m + n);
}
else return (m + n);
}
else return 0;
}
//直接采用递归方法:
//递归模型如下:
//f(bt) = 0 当bt == NULL
//f(bt) = 1 当bt == 单分支结点
//f(bt) = f(bt->lchild) + f(bt->rchild) 当 其他情况
int onenodes2(BTNode *bt){
int m,n;
//空树返回0
if(bt == NULL){
return 0;
}
m = onenodes2(bt->lchild);
n = onenodes2(bt->rchild);
//单分支结点
if((bt->lchild == NULL && bt->rchild != NULL) || (bt->lchild != NULL && bt->rchild == NULL)){
return (1 + m + n);
}
//其他情况
else return m+n;
}
//2-求双分支结点数
//直接采用递归方法:
//递归模型如下:
//f(bt) = 0 当bt == NULL
//f(bt) = 1 当bt == 双分支结点
//f(bt) = f(bt->lchild) + f(bt->rchild) 当 其他情况
int twonodes(BTNode *bt){
int m,n;
//空树返回0
if(bt == NULL){
return 0;
}
m = twonodes(bt->lchild);
n = twonodes(bt->rchild);
//双分支结点
if(bt->lchild != NULL && bt->rchild != NULL){
return (1 + m + n);
}
//其他情况
else return m+n;
}
//设计算法复制一棵二叉树
//递归模型如下:
//f(bt) :nt = NULL 当bt == NULL
//f(bt) :由bt根结点复制产生nt根结点; 当bt != NULL
// f(bt->lchild,nt->lchild)
// f(bt->rchild,nt->rchild)
void CopyBTree(BTNode *bt,BTNode *&newt){
if(bt != NULL){
newt = (BTNode *)malloc(sizeof(BTNode));
newt->data = bt->data;
CopyBTree(bt->lchild, newt->lchild);
CopyBTree(bt->rchild, newt->rchild);
}
else newt = NULL;
}
//设计算法,由给定的二叉树的二叉链存储结构建立其对应的顺序存储结构
//递归模型如下:
//f(bt,sb,i) :sb[i] = '#' 当bt == NULL
//f(bt,sb,i) :sb[i] = bt->data 其他情况
// f(bt->lchild,sb,2*i)
// f(bt->rchild,sb,2*i+1)
void trans1(BTNode *bt,SqBinTree &sb,int i){
//i的初值为根结点编号【1】
if(bt != NULL){
sb[i] = bt->data;
trans1(bt->lchild,sb,2*i);
trans1(bt->rchild,sb,2*i+1);
}
else sb[i] = '#';
}
//设计一个算法,有给定的二叉树顺序存储结构建立其对应的二叉链存储结构
void trans2(BTNode *&bt,SqBinTree sb,int i){
//i的初值为根结点编号【1】
if(i < MAXSIZE && sb[i] != '#'){
bt = (BTNode *)malloc(sizeof(BTNode));
bt->data = sb[i];
//递归建立左子树、右子树
trans2(bt->lchild,sb,2*i);
trans2(bt->rchild,sb,2*i+1);
}
else bt = NULL;
}
//设计算法,输出每一个叶子结点的所有祖先结点
void ancestor1(BTNode *bt,ElemType path[],int pathlen){
int i;
if(bt != NULL){
//bt为叶子结点:
if(bt->lchild == NULL && bt->rchild == NULL){
printf(" %c结点的所有祖先结点: ",bt->data);
for(i = pathlen - 1;i >= 0;i--){
printf("%c ",path[i]);
}
printf("\n");
}
else{
//将当前结点放在路径中
path[pathlen] = bt->data;
//path中元素个数增加1
pathlen++;
//递归扫描左右子树
ancestor1(bt->lchild,path,pathlen);
ancestor1(bt->rchild,path,pathlen);
}
}
}
//采用层次遍历求解
void ancestor2(BTNode *bt){
BTNode *p;
int i;
//qu存放队中元素
struct{
//存放结点指针
BTNode *s;
//存放起双亲结点在qu中的下标
int parent;
}qu[MAXSIZE];
int front = -1,rear = -1;
//根结点进队;它没有双亲,其parent置为-1
rear++;
qu[rear].s = bt;
qu[rear].parent = -1;
while(front != rear){
//出队结点p,它在qu中的下标为front
front++;
p = qu[front].s;
//若p为叶子结点
if(p->lchild != NULL && p->rchild != NULL){
printf(" %c结点的所有祖先结点:",p->data);
i = qu[front].parent;
while(i != -1){
printf("%c ",qu[i].s->data);
i = qu[i].parent;
}
printf("\n");
}
//p有左孩子,将左孩子进队
if(p->lchild != NULL){
rear++;
qu[rear].s = p->lchild;
//双亲为front结点
qu[rear].parent = front;
}
if(p->rchild != NULL){
rear++;
qu[rear].s = p->rchild;
qu[rear].parent = front;
}
}
}
int main(){
return 0;
}
本文介绍了大二学生在C++数据结构课程中,针对OpenJudge平台提交的部分代码进行回顾和分析,包括二叉树的创建、销毁、遍历及各种操作算法。通过实例展示了括号法创建二叉树、层次遍历等,并提供了交流讨论的平台。

2310

被折叠的 条评论
为什么被折叠?



