王道数据结构代码---第五章:二叉树(重要)

目录

 二叉树的层次建树 (必须掌握)

        二叉树结构体定义   

        辅助建树的队列的结构体

         建树的主要代码

二叉树的遍历(必须掌握)

        前序遍历

        中序遍历

        后序遍历

        非递归实现中序遍历

        层次遍历

        完整代码

线索二叉树

        结构体定义

        建立二叉搜索树

        完整代码

 二叉排序树(二叉查找树)

        定义

        结构体定义     

        创建二叉排序树

        插入结点操作

        查找结点值为key的元素

        删除结点  

       完整代码  


树的性质

王道数据结构代码---第五章:二叉树(重要)_第1张图片

        二叉树五种形态

王道数据结构代码---第五章:二叉树(重要)_第2张图片

 二叉树的层次建树 (必须掌握)

        二叉树结构体定义   

//二叉树结构体定义
typedef struct BiTNode {
	BiElemType c;   //数据域
	struct BiTNode* lchild;  //左孩子指针
	struct BiTNode* rchild;   //右孩子指针
}BiTNode, * BiTree;

        辅助建树的队列的结构体

typedef struct tag 
{
	BiTree p;    //树的某一个结点的地址值
	struct tag* pnext;
}tag_t, * ptag_t;

         建树的主要代码

BiTree pnew;
	int i, j, pos;
	char c;
	BiTree tree = NULL;  //树根置空
	ptag_t phead = NULL, ptail = NULL, listpnew = NULL, pcur = NULL;//phead就是队列头,ptail就是队列尾
	//abcdefghij
	while (scanf("%c", &c) != EOF)
	{
		if (c == '\n')
		{
			break;
		}
		pnew = (BiTree)calloc(1, sizeof(BiTNode)); //calloc申请空间并对空间进行初始化,赋值为0
		pnew->c = c;//数据放进去
		listpnew = (ptag_t)calloc(1, sizeof(tag_t));//给队列结点申请空间
		listpnew->p = pnew;
		if (tree == NULL)
		{
			tree = pnew;//树的根
			phead = listpnew;//队列头
			ptail = listpnew;//队列尾
			pcur = listpnew;
			continue;
		}
		else 
		{
			ptail->pnext = listpnew;//新结点放入链表,通过尾插法
			ptail = listpnew;//ptail指向队列尾部
		}//pcur始终指向要插入的结点的位置
		if (pcur->p->lchild == NULL)//如何把新结点放入树,也就是判断根节点的左边为空 
		{
			pcur->p->lchild = pnew;//把新结点放到要插入结点的左边
		}
		else if (pcur->p->rchild == NULL)
		{
			pcur->p->rchild = pnew; //把新结点放到要插入结点的右边
			pcur = pcur->pnext; //左右都放了结点后,pcur指向队列的下一个
		}
	}

二叉树的遍历(必须掌握)

采用递归实现

 遍历的示意图

王道数据结构代码---第五章:二叉树(重要)_第3张图片

        前序遍历

//前序遍历,前序遍历就是深度优先遍历
void preOrder(BiTree p)
{
	if (p != NULL)
	{
		putchar(p->c);//等价于visit函数    ,打印根节点 
		preOrder(p->lchild);  //打印左子树 
		preOrder(p->rchild);  //打印右子树 
	}
}

        中序遍历

//中序遍历  
void InOrder(BiTree p)
{
	if (p != NULL)
	{
		InOrder(p->lchild);//打印左子树 
		putchar(p->c);  //打印根节点 
		InOrder(p->rchild); //打印右子树 
	}
}

        后序遍历

// 后序遍历
void PostOrder(BiTree p)
{
	if (p != NULL)
	{
		PostOrder(p->lchild); //打印左子树 
		PostOrder(p->rchild);//打印右子树 
		putchar(p->c); //打印根结点 
	}
}

        非递归实现中序遍历

//中序遍历非递归,非递归执行效率更高
void InOrder2(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); putchar(p->c);
			p = p->rchild;
		}
	}
}

        层次遍历

//层次遍历,层序遍历,广度优先遍历
void LevelOrder(BiTree T)
{
	LinkQueue Q;//辅助队列
	InitQueue(Q);//初始化队列
	BiTree p;
	EnQueue(Q, T);//树根入队
	while (!IsEmpty(Q))
	{
		DeQueue(Q, p);//出队当前结点并打印
		putchar(p->c);
		if (p->lchild != NULL) //入队左孩子
			EnQueue(Q, p->lchild);
		if (p->rchild != NULL)  //入队右孩子
			EnQueue(Q, p->rchild);
	}
}

        完整代码

#define  _CRT_SECURE_NO_WARNINGS   //解决scanf编译报错问题
#include "function.h"


typedef char BiElemType;
//二叉树结构体定义
typedef struct BiTNode {
	BiElemType c;   //数据域
	struct BiTNode* lchild;  //左孩子指针
	struct BiTNode* rchild;   //右孩子指针
}BiTNode, * BiTree;

//辅助建树的队列
typedef struct tag 
{
	BiTree p;    //树的某一个结点的地址值
	struct tag* pnext;
}tag_t, * ptag_t;

//递归实现
//abdhiejcfg  前序遍历,前序遍历就是深度优先遍历
void preOrder(BiTree p)
{
	if (p != NULL)
	{
		putchar(p->c);//等价于visit函数    ,打印根节点 
		preOrder(p->lchild);  //打印左子树 
		preOrder(p->rchild);  //打印右子树 
	}
}
//中序遍历  hdibjeafcg
void InOrder(BiTree p)
{
	if (p != NULL)
	{
		InOrder(p->lchild);//打印左子树 
		putchar(p->c);  //打印根节点 
		InOrder(p->rchild); //打印右子树 
	}
}
//hidjebfgca  后序遍历
void PostOrder(BiTree p)
{
	if (p != NULL)
	{
		PostOrder(p->lchild); //打印左子树 
		PostOrder(p->rchild);//打印右子树 
		putchar(p->c); //打印根结点 
	}
}

//中序遍历非递归,非递归执行效率更高,考的概率很低
void InOrder2(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); putchar(p->c);
			p = p->rchild;
		}
	}
}

//层次遍历,层序遍历,广度优先遍历
void LevelOrder(BiTree T)
{
	LinkQueue Q;//辅助队列
	InitQueue(Q);//初始化队列
	BiTree p;
	EnQueue(Q, T);//树根入队
	while (!IsEmpty(Q))
	{
		DeQueue(Q, p);//出队当前结点并打印
		putchar(p->c);
		if (p->lchild != NULL) //入队左孩子
			EnQueue(Q, p->lchild);
		if (p->rchild != NULL)  //入队右孩子
			EnQueue(Q, p->rchild);
	}
}

int main()
{
	BiTree pnew;
	int i, j, pos;
	char c;
	BiTree tree = NULL;  //树根置空
	ptag_t phead = NULL, ptail = NULL, listpnew = NULL, pcur = NULL;//phead就是队列头,ptail就是队列尾
	//abcdefghij
	while (scanf("%c", &c) != EOF)
	{
		if (c == '\n')
		{
			break;
		}
		pnew = (BiTree)calloc(1, sizeof(BiTNode)); //calloc申请空间并对空间进行初始化,赋值为0
		pnew->c = c;//数据放进去
		listpnew = (ptag_t)calloc(1, sizeof(tag_t));//给队列结点申请空间
		listpnew->p = pnew;
		if (tree == NULL)
		{
			tree = pnew;//树的根
			phead = listpnew;//队列头
			ptail = listpnew;//队列尾
			pcur = listpnew;
			continue;
		}
		else 
		{
			ptail->pnext = listpnew;//新结点放入链表,通过尾插法
			ptail = listpnew;//ptail指向队列尾部
		}//pcur始终指向要插入的结点的位置
		if (pcur->p->lchild == NULL)//如何把新结点放入树,也就是判断根节点的左边为空 
		{
			pcur->p->lchild = pnew;//把新结点放到要插入结点的左边
		}
		else if (pcur->p->rchild == NULL)
		{
			pcur->p->rchild = pnew; //把新结点放到要插入结点的右边
			pcur = pcur->pnext; //左右都放了结点后,pcur指向队列的下一个
		}
	}
	printf("--------前序遍历----------\n");//也叫先序遍历,先打印当前结点,打印左孩子,打印右孩子
	preOrder(tree);    //根+左+右
	printf("\n--------中序遍历------------\n");//先打印左孩子,打印父亲,打印右孩子
	InOrder(tree);   //左+根+右
	printf("\n--------后序遍历------------\n");//先打印左孩子,打印右孩子,最后打印父亲
	PostOrder(tree);   //左+右+根
	printf("\n--------中序遍历非递归------\n");//重要性低
	InOrder2(tree);
	printf("\n--------层次遍历-----------\n");
	LevelOrder(tree);
	printf("\n");

	return 0;
}

线索二叉树

概念:当一个结点的左孩子指针或者右孩子指针是空着的,线索二叉树就是不让结点的左右孩子指针空着。

        结构体定义

typedef struct ThreadNode {
	ElemType data;    //数据域
	struct ThreadNode* lchild, * rchild;   //左孩子指针,右孩子指针
	int ltag, rtag;
}ThreadNode, * ThreadTree;

        建立二叉搜索树

void BulidThreadTree(ThreadTree& T)
{
	ThreadTree arr[5];
	int i;
	for (i = 0; i < 5; i++)
	{
		arr[i] = (ThreadTree)malloc(sizeof(ThreadNode));
		memset(arr[i], 0, sizeof(ThreadNode));
		arr[i]->data = 'A' + i;
	}
	arr[0]->lchild = arr[1];
	arr[0]->rchild = arr[2];
	arr[1]->rchild = arr[3];
	arr[2]->lchild = arr[4];
	T = arr[0];
}

        完整代码

#include 
#include 
#include 

typedef char ElemType;
typedef struct ThreadNode {
	ElemType data;    //数据域
	struct ThreadNode* lchild, * rchild;   //左孩子指针,右孩子指针
	int ltag, rtag;
}ThreadNode, * ThreadTree;
//手工建线索树,总计5个结点
void BulidThreadTree(ThreadTree& T)
{
	ThreadTree arr[5];
	int i;
	for (i = 0; i < 5; i++)
	{
		arr[i] = (ThreadTree)malloc(sizeof(ThreadNode));
		memset(arr[i], 0, sizeof(ThreadNode));
		arr[i]->data = 'A' + i;
	}
	arr[0]->lchild = arr[1];
	arr[0]->rchild = arr[2];
	arr[1]->rchild = arr[3];
	arr[2]->lchild = arr[4];
	T = arr[0];
}

void InThread(ThreadTree& p, ThreadTree& pre)
{
	if (p != NULL) {
		InThread(p->lchild, pre);//递归找树的左孩子
		if (p->lchild == NULL) {//左边为NULL,填写当前结点的前驱
			p->lchild = pre;
			p->ltag = 1;
		}
		if (pre != NULL && pre->rchild == NULL) {
			//pre节点右孩子为NULL,就让其指向后继节点,而后继结点刚好就是p
			pre->rchild = p;
			pre->rtag = 1;
		}
		pre = p;
		InThread(p->rchild, pre);
	}
}
void CreateInThread(ThreadTree T)
{
	ThreadTree pre = NULL;//使用辅助指针pre
	if (T != NULL) {
		InThread(T, pre);
		pre->rchild = NULL;
		pre->rtag = 1;
	}
}
//中序序列下的第一个结点
ThreadNode* Firstnode(ThreadNode* p)
{
	while (p->ltag == 0)
		p = p->lchild;
	return p;
}
//p在中序序列下的后继结点
int main()
{
	ThreadTree T;
	ThreadTree p;
	BulidThreadTree(T);
	CreateInThread(T);//构建线索二叉树
	p = Firstnode(T);
	printf("最左下结点值为 %c\n", p->data);
	system("pause");
}

 二叉排序树(二叉查找树)

        定义

王道数据结构代码---第五章:二叉树(重要)_第4张图片

          结构体定义     

typedef struct BSTNode{   
	KeyType key;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BiTree;

        创建二叉排序树

//创建二叉排序树
void Creat_BST(BiTree &T,KeyType str[],int n)
{
	T=NULL;
	int i=0;
	while(i

        插入结点操作

//插入操作,递归实现
int BST_Insert(BiTree &T,KeyType k)
{
	if(T==NULL)
	{	
		T=(BiTree)malloc(sizeof(BSTNode));  //为新节点申请空间
		T->key=k;   //
		T->lchild=T->rchild=NULL;   //左孩子右孩子为空
		return 1;//代表插入成功
	}
	else if(k==T->key)
		return 0;//发现相同元素,就不插入
	else if(kkey)    //如果要插入的结点,小于当前结点
		return BST_Insert(T->lchild,k);   //放入左孩子中,递归实现
	else
		return BST_Insert(T->rchild,k);   //放入右孩子中,递归实现
}

          查找结点值为key的元素

//查找结点值为key的元素,非递归实现的
BSTNode *BST_Search(BiTree T,KeyType key,BiTree &p)
{
	p=NULL;
	while(T!=NULL&&key!=T->key)
	{
		p=T;
		if(keykey) 
			T=T->lchild;//比当前节点小,就左边找
		else 
			T=T->rchild;//比当前节点大,右边去
	}
	return T;
}

          删除结点  

//删除
void DeleteNode(BiTree &root,KeyType x){
    if(root == NULL){
        return;
    }
    if(root->key>x){
        DeleteNode(root->lchild,x);
    }else if(root->keyrchild,x);
    }else{ //查找到了删除节点
        if(root->lchild == NULL){ //左子树为空
           BiTree tempNode = root;
           root = root->rchild;
           free(tempNode);
        }else if(root->rchild == NULL){ //右子树为空
           BiTree tempNode = root;//临时指针
           root = root->lchild;
           free(tempNode);
        }else{  //左右子树都不为空
            //一般的删除策略是左子树的最大数据 或 右子树的最小数据 代替要删除的节点(这里采用查找左子树最大数据来代替)
            BiTree tempNode = root->lchild;
            if(tempNode->rchild!=NULL){
                tempNode = tempNode->rchild;
            }
            root->key = tempNode->key;
            DeleteNode(root->lchild,tempNode->key);
        }
    }
}

         完整代码  

#include 
#include 


typedef int KeyType;
typedef struct BSTNode{   
	KeyType key;
	struct BSTNode *lchild,*rchild;
}BSTNode,*BiTree;
//54,20,66,40,28,79,58
//插入操作,递归实现
int BST_Insert(BiTree &T,KeyType k)
{
	if(T==NULL)
	{	
		T=(BiTree)malloc(sizeof(BSTNode));  //为新节点申请空间
		T->key=k;   //
		T->lchild=T->rchild=NULL;   //左孩子右孩子为空
		return 1;//代表插入成功
	}
	else if(k==T->key)
		return 0;//发现相同元素,就不插入
	else if(kkey)    //如果要插入的结点,小于当前结点
		return BST_Insert(T->lchild,k);   //放入左孩子中,递归实现
	else
		return BST_Insert(T->rchild,k);   //放入右孩子中,递归实现
}
//创建二叉排序树
void Creat_BST(BiTree &T,KeyType str[],int n)
{
	T=NULL;
	int i=0;
	while(ikey)
	{
		p=T;
		if(keykey) 
			T=T->lchild;//比当前节点小,就左边找
		else 
			T=T->rchild;//比当前节点大,右边去
	}
	return T;
}
//这个书上没有二叉排序树
void DeleteNode(BiTree &root,KeyType x){
    if(root == NULL){
        return;
    }
    if(root->key>x){
        DeleteNode(root->lchild,x);
    }else if(root->keyrchild,x);
    }else{ //查找到了删除节点
        if(root->lchild == NULL){ //左子树为空
           BiTree tempNode = root;
           root = root->rchild;
           free(tempNode);
        }else if(root->rchild == NULL){ //右子树为空
           BiTree tempNode = root;//临时指针
           root = root->lchild;
           free(tempNode);
        }else{  //左右子树都不为空
            //一般的删除策略是左子树的最大数据 或 右子树的最小数据 代替要删除的节点(这里采用查找左子树最大数据来代替)
            BiTree tempNode = root->lchild;
            if(tempNode->rchild!=NULL){
                tempNode = tempNode->rchild;
            }
            root->key = tempNode->key;
            DeleteNode(root->lchild,tempNode->key);
        }
    }
}

void InOrder(BiTree T)
{
	if(T!=NULL)
	{
		InOrder(T->lchild);
		printf("%3d",T->key);
		InOrder(T->rchild);
	}
}

//二叉排序树的创建,中序遍历,查找,删除
int main()
{
	BiTree T;   //树根
	BiTree parent;  //存储父亲结点的地址值
	BiTree search;
	KeyType str[]={54,20,66,40,28,79,58};//将要进入二叉排序树的元素值
	Creat_BST(T,str,7);   
	InOrder(T);
	printf("\n");
	search=BST_Search(T,40,parent);
	if(search)
	{
		printf("找到对应结点,值=%d\n",search->key);
	}else{
		printf("未找到对应结点\n");
	}
	DeleteNode(T,66);
	InOrder(T);
	printf("\n");
	return 0;
}

你可能感兴趣的:(数据结构)