二叉树打印树形

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include"MyBST.h"
using namespace std;

int main()
{
    cout<<"Please enter the numbers:"<<endl;//提示用户输入
    MyBST *mybst = new MyBST( );//构造类MyBST的对象 mybst,指针类型
    while(cin.peek()!='\n')//peek 相当于偷看一眼,再放回去
    {                       //当下一个读入的不是回车时
        int temp;
        cin>>temp;//读入数值
        mybst->insertNode(temp);//插入树中
    }

   mybst->output();//打印二叉树图形

    cout<<"Please enter the number to delete:"<<endl;//提示用户输入要删除的数值
    int deletex;
    while(scanf("%d",&deletex)!=EOF)//读入以文件结尾为止。控制台下使用ctrl+z+回车
    {
        Node *temp=mybst->findByKey(deletex);//创建值为deletex的节点temp
    	if(temp==nullptr)
    		cout<<"无 "<<deletex<<endl;//没有该节点,无法删除
    	else
    		mybst->deleteNode(temp);//删除该节点temp
     mybst->output();//打印
	}


}

主函数注释很全了。。。

题目要求:输入数字,以回车结束,建立二叉搜索树,并打印树形。

输入要删除的数字,重新打印树形。

 

二叉树的定义和基本函数   搬砖:https://www.cnblogs.com/coffeeSS/p/5452719.html

打印树形那里,其实是一个中序遍历,根在左,叶子在右。深度每增加一层,前面打印的空格就越多。

#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<cstdlib>

using namespace std;

//节点结构
struct Node{
    Node(int k=0):key(k){}//初始化
    Node* parent = nullptr;//父节点
    Node* left = nullptr;//左孩子
    Node* right = nullptr;//右孩子
    int key;//对应的数值
};


class MyBST{
private:
    Node* root=nullptr;//根节点
    Node* findSuccessor(Node* n);//寻找后继节点
    Node* findPredecessor(Node* n);//寻找前驱节点
    void  insertNode(Node* n);//插入节点
    void output_impl(Node* n, bool left, string indent);//输出函数需要调用的函数,方便打印树形
    void output(Node* root);//遍历输出所有节点
public:
    MyBST(){};//构造函数
    Node* getRoot(){ return root; }//返回根节点
    Node* findByKey(int k);//寻找数值为k的节点
    void insertNode(int k);//插入数值为k的节点
    void output()//输出树形
    {
        output(root);
    }
    void deleteNode(Node* n);//删除节点
};



Node* MyBST::findByKey(int k){
    Node* temp = root;//获取根节点
    while (temp != nullptr){
        if (k == temp->key)//当key相等的时候返回匹配节点
           {
             return temp;
           }
        temp = k < temp->key ? temp->left : temp->right;//通过比较key的值来决定搜索向哪一棵子树进行
    }

    return nullptr;
}


Node* MyBST::findPredecessor(Node* n)//寻找前驱节点
{
    if (n->left != nullptr){//若x的左子树不为空,
        n = n->left; //则x前驱是x节点左子树里最靠右的那个节点
        while (n->right != nullptr)
            n = n->right;
        return n;
    }
    while (n->parent != nullptr&&n->parent->left == n)//如果x的左子树为空,
        n = n->parent;
    return n->parent;//那么我们就要向上找x的第一个有右孩子且左子树里没有x节点的祖先
}

Node* MyBST::findSuccessor(Node* n)//寻找后继节点
{
    if (n->right != nullptr)
	{
		//若n的右子树不为空,则n后继是x节点右子树里最靠左的那个节点
        n = n->right;
        while (n->left != nullptr)
            n = n->left;
        return n;
    }
    while (n->parent != nullptr&&n->parent->right == n)//如果n的左子树为空
        n = n->parent;//那么我们就要向上找x的第一个有右孩子且左子树里没有x节点的祖先
    return n->parent;
}



void MyBST::output_impl(Node* n, bool left, string  indent)//输出树形
{
    if (n->right)
    {
       output_impl(n->right, false, indent + "      " );//右孩子则将left置为false,进入下一层时字符串增加空格
    }
    cout << indent;//输出字符串
    cout << (left ? '\\' : '/');//打印“树枝”的方向
    cout << "-----";//打印树枝
    cout << n->key << endl;//打印数值
    if (n->left)
    {
      output_impl(n->left, true, indent + "      " );//左孩子则将left置为true,进入下一层时字符串增加空格
    }
}

void MyBST::output(Node* n)//中序遍历
{
    if (n->right)
    {
        output_impl(n->right, false, "");
    }
    cout << n->key << endl;
    if (n->left)
    {
        output_impl(n->left, true, "");
    }
}



void MyBST::insertNode(int k)//公有函数中的插入数值为k的节点
{
    Node* n = new Node(k);//生成节点
    insertNode(n);//调用私有函数,插入节点
}

void MyBST::insertNode(Node* n)//私有函数中,插入节点
{
    Node* temp = root;
    if (temp==nullptr){//树为空就设置根节点
        root = n;
        return;
    }
    while (true){//这个循环里有一个大的if-else结构,用来决定插入到左子树还是右子树
        if (temp->key > n->key){//进入左子树
            if (temp->left != nullptr)//if-else结构判断是否已经到达要插入的地方
                temp = temp->left;//到达则替换,没有则深入
            else{
                temp->left = n;
                n->parent = temp;
                return;
            }
        }
        else{
            if (temp->right != nullptr)//进入右子树
                temp = temp->right;
            else{
                temp->right = n;
                n->parent = temp;
                return;
            }
        }
    }
}

void MyBST::deleteNode(Node* n)//删除节点
{
    Node* temp;//用来存取代n节点位置的节点,下面的if分三种情况确定取代n节点位置的节点temp的取值

    if (n->left == nullptr&&n->right == nullptr)//情况一:n没有孩子节点
        temp = nullptr;

    else if (n->left == nullptr || n->right == nullptr)
	{
		//情况二:n有一个孩子节点
        temp = (n->left == nullptr) ? n->right : n->left;//我们用这个孩子节点当做取代n的节点
        temp->parent = n->parent;//因为temp要取代n,所以要用temp复制n的属性,因为temp就是n的孩子节点之一,
    }                           //且另一个孩子节点是nullptr,所以n的孩子节点的信息不用复制
    else
	{
		//情况三:n有两个孩子节点,双支节点   y--temp
        temp = findSuccessor(n);//我们用n节点的后继y当做取代n的节点
        Node* successor_right;//y只可能有一个右孩子或者没有孩子,我们先要让y的右孩子取代y,再让y取代n
        if (temp->right == nullptr)//如果y没有孩子,则用nullptr取代y
            successor_right = nullptr;
        else{
            successor_right = temp->right;
            successor_right->parent = temp->parent;//y有右孩子的时候要处理右孩子的父节点
        }

        if (temp->parent->left == temp)//这个if用来让y的父节点指向取代y的节点
            temp->parent->left = successor_right;
        else
            temp->parent->right = successor_right;
        //接下来要让y取代n了,其实我们只需要把y的key值给n就行了,然后直接退出,不需要再修改其他的部分了
        n->key = temp->key;
        delete temp;
        return;
    }
    //情况一和情况二到此为止取代n节点的temp已经确定,而且当temp不是nullptr的时候,
    //temp也已经复制了必要的n的属性,剩下的就是让n的父节点指向temp了
    //注意被删除的节点有可能是根节点,所以当我们发现被删除的是根节点时,不需要让n的父节点指向temp,
    //因为n没有父节点了,但是这个时候必须修改root指针的指向
    if (n->parent != nullptr){
        if (n->parent->left == n)
            n->parent->left = temp;
        else
            n->parent->right = temp;
    }
    else
        root = temp;//修改root指针的指向
    delete n;
}

实验周的代码。

反正排名很低,没人看哈哈哈。

结果大概酱紫:

成绩出来了才敢放出来

/* 这是一个在字符环境中,用ASCII码打印二叉树形状的算法。 在Linux控制台下写的例题,在DOS中稍有点乱。 采用层次遍法。 算法拙劣,仅供初学者做练习,(本人也是初学者,自学数据结构,刚好学到这二叉树这一章, 半路出家,基础差有点吃力头大,搞几个二叉的例题,却不知道其构造形状, 想调用图形API做个美观点的,却有点偏离本章的学习目的,只好用字符打印, linux环境中打印的还可以,DOS中有点不稳定,如果您有更好的算法一定不吝赐教。 我的QQ:137241638 mail:hnflcp@139.com */ #include <stdio.h> #include <stdlib.h> #define MaxSize 100 //Pstart是二叉树根结点在一行中的位置,一行最能打印124个字符,取其1/2。 //如果你的屏不够宽的话,可以输出文本文件里, aa.exe>>aa.txt #define Pstart 40 typedef struct bstnode { int key, data, bf; struct bstnode *lchild, *rchild; }BSTNode; typedef struct pnode //为打印二叉树建了一个结构。 { int key; //关键字数据1 int data; //关键字数据2 struct pnode *lchild, //左孩子 *rchlid, //右孩子 *parent; //父节点 int lrflag, //标记本节点是左孩子(等于0时),还是右孩子(等于1时) space, //存储本节点打印位置 level; //存储本节点所在层次。 }PBSTNode; /*建立二叉树。 用括号表示法表示二叉树字符串,创建二叉树。 */ BSTNode* CreateBSTNode(char *s) { char ch; BSTNode *p=NULL, *b=NULL, *ps[MaxSize]; int top=-1, tag=-1; ch=*s; while(ch) { switch(ch) { case '(':ps[++top]=p;tag=1;break; case ',':tag=2;break; case ')':top--;break; default: p=(BSTNode*)malloc(sizeof(BSTNode)); p->data=ch; p->lchild=p->rchild=NULL; if(b==NULL) b=p; else { switch(tag) { case 1:ps[top]->lchild=p;break; case 2:ps[top]->rchild=p;break; } } } ch=*(++s); } return b; } //用适号表示法打印二叉树。 void DispBSTNode(BSTNode *b) { if(b!=NULL) { printf("%d",b->key); if(b->lchild!=NULL||b->rchild!=NULL) { printf("("); DispBSTNode(b->lchild); if(b->rchild!=NULL)printf(","); DispBSTNode(b->rchild); printf(")"); } } } int BSTNodeHeight(BSTNode *b) { int lchildh,rchildh; if(b==NULL)return 0; else { lchildh=BSTNodeHeight(b->lchild); rchildh=BSTNodeHeight(b->rchild); return (lchildh>rchildh)?(lchildh+1):(rchildh+1); } } /*建立一个二叉树打印结点的信息, 只被int CreatePBSTNode(BSTNode *b,PBSTNode *pqu[])调用*/ void SetPBSTNodeInfo(BSTNode *b,PBSTNode *parent,PBSTNode *pb,int level,int lrflag) { int f=3; pb->data=b->data; pb->key =b->key; pb->parent=parent; pb->level=level; pb->lrflag=lrflag; pb->space=-1; } /*用层次遍历法,BSTNode结构存储的二叉树转换为,PBSTNode结构的二叉树*/ int CreatePBSTNode(BSTNode *b,PBSTNode *pqu[]) { BSTNode *p; BSTNode *qu[MaxSize]; int front=-1, rear=-1; rear++; qu[rear]=b; pqu[rear]=(PBSTNode*)malloc(sizeof(PBSTNode)); SetPBSTNodeInfo(b,NULL,pqu[rear],1,-1); while(rear!=front) { front++; p=qu[front]; if(p->lchild!=NULL) { rear++; qu[rear]=p->lchild; pqu[rear]=(PBSTNode*)malloc(sizeof(PBSTNode)); SetPBSTNodeInfo(p->lchild,pqu[front],pqu[rear],pqu[front]->level+1,0); } if(p->rchild!=NULL) { rear++; qu[rear]=p->rchild; pqu[rear]=(PBSTNode*)malloc(sizeof(PBSTNode)); SetPBSTNodeInfo(p->rchild,pqu[front],pqu[rear],pqu[front]->level+1,1); } } return rear; } //打印一层结点,及该层结点与父结点的连线路径。 void PBSTNodePrint_char(PBSTNode *pb[],int n,int h) { int l=-1, r=0, i,j,k, end; char c; PBSTNode *p; if(n<=0||h<=0) { return; } else if(pb[0]->level==1) { for(i=0;i<pb[0]->space;i++) printf(" "); printf("%c",pb[0]->data); printf("\n"); return; } h=h-pb[0]->level+2; for(k=0;k<h;k++) { j=0; l--; r++; for(i=0;i<n;i++)//打印线条 { p=pb[i]; end=(p->lrflag==0)?l:r; end+=p->parent->space; for(;j<end;j++) printf(" "); c=(p->lrflag==0)?'/':'\\'; printf("%c",c); } printf("\n"); } for(i=0;i<n;i++)//计算本层结点打印位置 { p=pb[i]; if(p->lrflag==0) p->space=p->parent->space+l; else p->space=p->parent->space+r; } for(i=0,j=0;i<n;i++)//打印关键字数据 { p=pb[i]; for(;j<p->space;j++) printf(" "); printf("%c",p->data); } printf("\n"); } //循环打印所有层的数据 void DispBTree(BSTNode *b) { int n,i,j,high, level; PBSTNode *p; PBSTNode *pqu[MaxSize]; PBSTNode *levelpqu[MaxSize]; n=CreatePBSTNode(b,pqu); high=BSTNodeHeight(b); j=0; level=1; pqu[0]->space=Pstart; for(i=0;i<=n;i++) { p=pqu[i]; if(p->level==level) { levelpqu[j]=p; j++; } else { PBSTNodePrint_char(levelpqu,j,high); level=p->level; j=0; levelpqu[j]=p; j++; } } PBSTNodePrint_char(levelpqu,j,high); } void main() { int iDepth=0, iWidth=0, iCount=0; char *str1="A(B(D,E(H,X(J,K(L,M(T,Y))))),C(F,G(X,I)))"; char *str2="A(B(D(,G)),C(E,F))"; BSTNode *b=CreateBSTNode(str1); DispBSTNode(b);printf("\n"); iDepth=BSTNodeHeight(b); printf("Depth:%d\n",iDepth); DispBTree(b); }
下面是二叉树树形打印的Java代码实现: ``` public class BinaryTreePrinter { public static void printNode(TreeNode root) { int maxLevel = maxLevel(root); printNodeInternal(Collections.singletonList(root), 1, maxLevel); } private static void printNodeInternal(List<TreeNode> nodes, int level, int maxLevel) { if (nodes.isEmpty() || isAllElementsNull(nodes)) return; int floor = maxLevel - level; int edgeLines = (int) Math.pow(2, (Math.max(floor - 1, 0))); int firstSpaces = (int) Math.pow(2, (floor)) - 1; int betweenSpaces = (int) Math.pow(2, (floor + 1)) - 1; printWhitespaces(firstSpaces); List<TreeNode> newNodes = new ArrayList<>(); for (TreeNode node : nodes) { if (node != null) { System.out.print(node.val); newNodes.add(node.left); newNodes.add(node.right); } else { newNodes.add(null); newNodes.add(null); System.out.print(" "); } printWhitespaces(betweenSpaces); } System.out.println(""); for (int i = 1; i <= edgeLines; i++) { for (int j = 0; j < nodes.size(); j++) { printWhitespaces(firstSpaces - i); if (nodes.get(j) == null) { printWhitespaces(edgeLines + edgeLines + i + 1); continue; } if (nodes.get(j).left != null) System.out.print("/"); else printWhitespaces(1); printWhitespaces(i + i - 1); if (nodes.get(j).right != null) System.out.print("\\"); else printWhitespaces(1); printWhitespaces(edgeLines + edgeLines - i); } System.out.println(""); } printNodeInternal(newNodes, level + 1, maxLevel); } private static void printWhitespaces(int count) { for (int i = 0; i < count; i++) System.out.print(" "); } private static int maxLevel(TreeNode node) { if (node == null) return 0; return Math.max(maxLevel(node.left), maxLevel(node.right)) + 1; } private static boolean isAllElementsNull(List list) { for (Object object : list) { if (object != null) return false; } return true; } public static void main(String[] args) { TreeNode root = new TreeNode(1); root.left = new TreeNode(2); root.right = new TreeNode(3); root.left.left = new TreeNode(4); root.left.right = new TreeNode(5); root.right.left = new TreeNode(6); root.right.right = new TreeNode(7); printNode(root); } } class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } ``` 通过调用`printNode`方法,可以打印二叉树树形结构。其中`TreeNode`类表示二叉树节点,`val`表示节点的值,`left`和`right`分别表示节点的左右子节点。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值