2018/5/3
1.说在前面:由于数据结构已经学完了树,对于这种比较难的结构,说一点看法
2.二叉树:
1.由一个根节点和两个互不相较的子二叉树(左子树和右子树)组成的树
2.相关操作介绍:
1.创建结构体实现树的建立
对于树而言,依旧采取结构体指针的方式,树拥有着一个左子树,一个右子树和一个储存数据的位置
typedef struct Node
{
int data;
struct Node *leftchild;
struct Node *rightchild;
}BitreeNode;
2.创建二叉树的头结点
先分配空间,再将左子树和右子树的位置全部变为空即可
void InitBitree(BitreeNode**root)
{
*root = (BitreeNode*)malloc(sizeof(BitreeNode));//给结构体指针分配空间
(*root)->leftchild = NULL;
(*root)->rightchild = NULL;
}
3.在二叉树的左子树和右子树中插入结点
1.判断当前的树是否为空树
2.先保存当前结点的(左/右)子树,创建一个新的结点
3.将新创建的结点设置指向数值,然后插入设置结点和所保存子树之间(注意顺序:先和子树连接,再和当前结点连接)
4.返回所插入的值(注意函数设置的返回值:为结构体指针,方便返回插入结点)
//二叉树中左结点插入数据
//当前结点curr不为空,在curr结点的左子树中插入元素为x的新左子树
BitreeNode*InsertLeftNode(BitreeNode*curr, int x)
{
BitreeNode *s,*t;
//判断是否存在结点可以增加左右孩子结点
if (curr == NULL)
{
return NULL;
}
t = curr->leftchild;//保存curr结点的左子树
s = (BitreeNode*)malloc(sizeof(BitreeNode));//创建新的子树
s->data = x;//该左子树的数据为x
s->leftchild = t;//相当于在curr和t之间多加了一层s
s->rightchild = NULL;
curr->leftchild = s;
return curr->leftchild;
}
//二叉树中右结点插入数据
//当前结点不为空,在curr结点的右子树中插入元素x的新右子树
BitreeNode*InsertRightNode(BitreeNode*curr, int x)
{
BitreeNode *s, *t;//*s表示增加的指针,*t表示原指针
//判断是否存在结点可以增加左右孩子结点
if (curr == NULL)
{
return NULL;
}
t = curr->rightchild;//保存curr结点的左子树
s = (BitreeNode*)malloc(sizeof(BitreeNode));//创建新的子树
s->data = x;//该左子树的数据为x
s->rightchild = t;//相当于在curr和t之间多加了一层s
s->leftchild = NULL;
curr->rightchild = s;
return curr->rightchild;
}
5.删除某个结点(左子树和右子树)
1.判断是否为空树
2.判断左子树和右子树是否为空,如果为空的话,直接返回NULL
不为空的话,将该结点的(左/右)结点进行删除
3.确定某个结点的左/右结点为空
4.返回结点
//如果curr非空,删除结点的左子树
BitreeNode *DeleteLeftTree(BitreeNode*curr)
{
if (curr == NULL || curr->leftchild == NULL)
{
return NULL;
}
//Destroy(&curr->leftchild);
curr->leftchild = NULL;
return curr;
}
//如果curr成功,删除所指结点的右子树
BitreeNode *DeleteRightTree(BitreeNode*curr)
{
if (curr == NULL || curr->rightchild == NULL)
{
return NULL;
}
// Destroy(&curr->rightchild);
curr->rightchild = NULL;
return curr;
}
//彻底删除(用于后序遍历)
/*void Destroy(BitreeNode **root)
{
if ((*root) != NULL && (*root)->leftchild != NULL)
{
Destroy(&(*root)->leftchild);//遍历
}
if ((*root) != NULL && (*root)->rightchild != NULL)
{
Destroy(&(*root)->rightchild);//遍历
}
free(*root);
//printf("删除成功\n");
}*/
5.遍历方法
采用了递归算法来实现(代码用前序遍历实现)
三种遍历方法的最终实现效果相同
1.前序遍历:根 左 右
2.中序遍历:左 根 右
3.后序遍历:左 右 根
注意使用遍历的方法 函数中的变量之一为visit函数
注意:采用的是递归的思路,函数的内部值之一为visit函数
void preOrder(BitreeNode*t, void Visit(int item))//对visit函数进行遍历树的值
{
if (t != NULL)
{
Visit(t->data);//根
preOrder(t->leftchild, Visit);//左
preOrder(t->rightchild, Visit);//右
}
}
void Visit(int item)
{
printf("%c", item);
}
6.打印数
1.这是一种特殊的中序遍历方法(右 根 左)
2.注意格式问题(空格和横线的使用)
3.采用递归
4.先访问右结点,再访问中间结点,再访问左结点
void printTree(BitreeNode*t, int n)//n代表着遍历的层数
{
//1.判断是否为空
if (t == NULL)
return;
printTree(t->rightchild, n++);//访问右结点
for (int i = 0; i < n; i++) printf(" ");//注意结构
if (n >= 0)
{
//printf("--------");
printf("%c\n", t->data);//实现根数据的显示
}
printTree(t->leftchild, n++);//访问左结点
}
7.查找数据
1.判断是否为空树
2.确定左结点有没有 如果有的话一直在左结点里找数
3.同样的方法在右结点里找
4.如果都没有 返回NULL;
BitreeNode* Search(BitreeNode*t, char x)
{
BitreeNode *p;
if (t->leftchild == NULL)
{
return NULL;//
}
if (t->leftchild != NULL)//说明该数字在左子树中出现
{
p = Search(t->leftchild, x);//在左子树中寻找
if (p != NULL)//get it
{
return p;
}
}
if (t->rightchild != NULL)
{
p = Search(t->rightchild, x);//在右子树中寻找
if (p != NULL)//get it
{
return p;
}
}
//如果既不在左指针也不在右指针中
//return 0;//退出程序
}
8.测试程序
//实现二叉树的创建和简单使用
//创建二叉树结构体
//1.初始化二叉树
//2.创建根节点
//3.创建左右子树
//4.删除左右子树
//5.直接删除
#include<stdio.h>
#include<stdlib.h>
#include"Bitree.h"
void main()
{
BitreeNode *root, *p, *pp;
InitBitree(&root);//创建一个根节点
p = InsertLeftNode(root, 'A');//创建第一个左结点
p = InsertLeftNode(p, 'B');
p = InsertLeftNode(p, 'D');
p = InsertRightNode(p,'G');
p = InsertRightNode(root->leftchild, 'C');
pp = p;
//创建最后的子结点
InsertLeftNode(p, 'E');
InsertRightNode(pp,'F');
printTree(root->leftchild, 0);
printf("\n进行前序遍历\n");
preOrder(root->leftchild, Visit);
Search(root, 'B');
printf("\n");
DeleteLeftTree(root->leftchild->leftchild);//删除根节点的左结点
printTree(root->leftchild, 0);
//Destroy(&root);//删除结点
system("pause");
}