链表实现二叉树


#include<winuser.inl>
#include<stdio.h>
#include <time.h>
#include <cstdlib>
#include <string.h>

/*
	  3 5 8 2 6 9 7
	  前序遍历:3 5 2 6 8 9 7
	  中序遍历:2 6 5 3 9 8 7
	  后序遍历:2 6 5 9 7 8 3

		树:
				3(0)
		5(1)			 8(2)
	2(3)  6(4)   9(5)   7(6)
*/

#define left 1
#define right 2

typedef struct tag_node
{
	int data;
	int index;
	struct tag_node   *pLeftChild, * pRightChild, * pParent;
}Node;

typedef struct tag_tree
{
	//该结构体指向树的根节点
	Node* root;
}Tree;

bool CreateTree(Tree** pTree, Node* pRoot);
void DestroyTree(Tree* pTree);
Node* SearchNodeindex(Node* pNode, int nodeIndex);  //节点层面
Node* SearchNode(Tree* pTree, int nodeindex);      //树层面
bool AddNode(Tree* pTree, int nodeindex, Node* pNode, int d1irection);
void DeleteN(Node* pNode, int direaction); //节点层面
bool DeleteNode(Tree* pTree, int nodeindex, Node* pNode);
void PreorderNode(Node* pNode);
void PreorderPrintTree(Tree* pTree);
void MidOrderNode(Node* pNode);
void MidOrderPrintTree(Tree* pTree);
void FinOrderNode(Node* pNode);
void  FinOrderPrintTree(Tree* pTree);

bool CreateTree(Tree** pTree, Node* pRoot)
{
	*pTree = (Tree*)malloc(sizeof(Tree));
	if (*pTree == NULL)
	{
		printf("failed\n");
		return false;
	}
	else
	{
		(*pTree)->root = (Node*)malloc(sizeof(Node));
		if ((*pTree)->root == NULL)
		{
			printf("failed\n");
			free(*pTree);   //这里分配失败,就把前面的内存释放掉
			return false;
		}
		//else    采用链表形式,不需要再左初始化
		//{
		//	//给树的所有节点赋初值为0
		//	for (int i = 0; i < MAXSIZE; i++)
		//	{
		//		(*pTree)->root[i].data = 0;
		//	}

		//	//创建的数的第一个节点需要有数据,将传进来的数据复制给第一个节点
		//	
		else
		{
			//(*pTree)->root[0] = *pRoot;
			*((*pTree)->root) = *pRoot;  //对象拷贝,与下面等价

			//(*pTree)->root->data = pRoot->data;
			//(*pTree)->root->index = pRoot->index;
			//(*pTree)->root->pLeftChild = NULL;
			//(*pTree)->root->pRightChild = NULL;
			//(*pTree)->root->pParent = NULL;

			return true;
		}
			
	}
}

void DeleteN(Node* pNode, int direaction)
{
	//判断传入进来的指针是否为空
	if (pNode != NULL)
	{
		DeleteN(pNode->pLeftChild, left);
		DeleteN(pNode->pRightChild, right);

		/*
		删除某一结点的左右子节点之后,进一步删除自己,删除自己之前
		需要将判断当前节点是属于自己父节点的左节点还是右节点,然后进一步
		将父节点对一个的左节点(右节点)置为null,然后再释放当前节点的内存
		*/
		if (direaction == left)
		{
			pNode ->pParent ->pLeftChild = NULL;
		}

		if (direaction == right)
		{
			pNode->pParent ->pRightChild = NULL;
		}

		free(pNode);
		pNode = NULL;
	}
}

void DestroyTree(Tree* pTree)
{
	//需要逐一销毁每一个节点
	DeleteN(pTree->root->pLeftChild, left);
	DeleteN(pTree->root->pRightChild, right);

	free(pTree->root);
	free(pTree);
}

//bool SearchNode(Tree* pTree, int nodeindex ,Node *node)
//{
//	这里的Node *node是用来存放要查找的那个数据
//	if (nodeindex < 0 || nodeindex >= MAXSIZE)
//	{
//		return false;
//	}
//	else
//	{
//		if (pTree->root[nodeindex].data == 0)
//		{
//			return false;
//		}
//		else
//		{
//			node->data = pTree->root[nodeindex].data;
//			return true;
//		}
//	}
//}

Node* SearchNodeindex(Node* pNode, int nodeIndex)
{
	if (pNode == NULL)
	{
		return NULL;
	}
	else
	{
		/*
		递归查找和传入索引一致的节点
		判断当前节点是否满足条件,不满足,则进一步查找当前节点的左子树,返回左子树
		的节点,以便递归进而寻炸左子树的左子树
		如果左子树是空的,那么只能进一步递归查找右子树
		*/
		if (pNode->index == nodeIndex)
		{
			return pNode;
		}
		else
		{
			Node* temp = NULL;
			temp = SearchNodeindex(pNode->pLeftChild, nodeIndex);
			if (temp != NULL)
			{
				return temp;
			}
			else
			{
				temp = SearchNodeindex(pNode->pRightChild, nodeIndex);
				return temp;
			}		
		}
	}
}

Node* SearchNode(Tree* pTree, int nodeindex)
{
	return SearchNodeindex(pTree->root, nodeindex); 
}

bool AddNode(Tree* pTree, int nodeindex, Node* pNode, int d1irection)
{
	/*
	1.找到要添加元素的节点
	2.判断该节点是否为空,为空,不能添加孩子,如果不为空,判断是要添加左孩子还是右
	,然后需要进一步判断(左)右孩子是否为空,为空才能添加子孩子
	*/
	Node* temp;
	Node* newNode = NULL;
	temp = SearchNode(pTree, nodeindex);

	//开辟一个节点的空间来存放传进来的 pNode节点数据,如果直接将temp指向pNode,
	//pNode申请的内存空间是在函数外面申请的,如果函数外面释放掉pNode的空间,那么Temp
	//就不知道指向哪了,所以最好的方式是在函数里面自己申请一个空间来存放节点数据

	if (temp != NULL)
	{
		if (d1irection == left)
		{
			if (temp->pLeftChild == NULL)
			{
				Node* newNode = (Node*)malloc(sizeof(Node));
				if (newNode == NULL)
				{
					return false;
				}
				else
				{
					*newNode = *pNode; //数据拷贝
					temp->pLeftChild = newNode;   //将temp的左孩子指向newnode

					//另外,每一个节点里面处理孩子节点,还有父亲节点
					newNode->pParent = temp; //将新节点的父节点指向temp

					return true;
				}			
			}
			else
			{
				return false;
			}
		}

		if (d1irection == right)
		{
			if (temp->pRightChild == NULL)
			{
				Node* newNode = (Node*)malloc(sizeof(Node));
				if (newNode == NULL)
				{
					return false;
				}
				else
				{
					*newNode = *pNode; //数据拷贝
					temp->pRightChild = newNode;   //将temp的左孩子指向newnode

					//另外,每一个节点里面处理孩子节点,还有父亲节点
					newNode->pParent = temp; //将新节点的父节点指向temp
					return true;
				}
			}
			else
			{
				return false;
			}
		}		
	}
	else
	{
		return false;
	}
}

bool DeleteNode(Tree* pTree, int nodeindex, Node* pNode)
{
	//DeleteNode这里是删除指定的节点,同时要删除指定节点之后的所有子节点
	//DeleteN作用是删除传入节点以下的全部节点,起始两个函数作用是一样的

	//需要先找到要删除的节点
	Node* temp;
	temp = SearchNode(pTree,nodeindex);
	if (temp != NULL)
	{
		//递归删除掉索引到的节点的全部子节点
		DeleteN(temp ->pLeftChild, left);
		DeleteN(temp ->pRightChild, right);

		//下面和在DeleteN里面一样,需要将当前的节点置为null,需要找到当前
		//节点的父节点,判断当前节点是父节点的左孩子还是右孩子
		if (temp->pParent->pLeftChild == temp)
		{
			temp->pParent->pLeftChild = NULL;
		}

		if (temp->pParent->pRightChild == temp)
		{
			temp->pParent->pRightChild = NULL;
		}
		free(temp);
		temp = NULL;
		return true;
	}
	else
	{
		return false;
	}
}

void PreorderNode(Node* pNode)
{
	if (pNode != NULL)
	{
		printf("%d ", pNode->data);
		PreorderNode(pNode->pLeftChild);
		PreorderNode(pNode->pRightChild);
	}
}

void PreorderPrintTree(Tree* pTree)
{
	//根左右
	printf("the tree is:\n");
	PreorderNode(pTree->root);
	printf("\n");
}

void MidOrderNode(Node* pNode)
{
	if (pNode != NULL)
	{
		MidOrderNode(pNode->pLeftChild);
		printf("%d ", pNode->data);
		MidOrderNode(pNode->pRightChild);
	}
}

void MidOrderPrintTree(Tree* pTree)
{
	//左中右
	printf("the tree is:\n");
	MidOrderNode(pTree->root);
	printf("\n");
}

void FinOrderNode(Node* pNode)
{
	if (pNode != NULL)
	{
		FinOrderNode(pNode->pLeftChild);
		FinOrderNode(pNode->pRightChild);
		printf("%d ", pNode->data);
	}
}

void  FinOrderPrintTree(Tree* pTree)
{
	//左右根
	printf("the tree is:\n");
	FinOrderNode(pTree->root);
	printf("\n");
}

int main()
{
	Tree* pTree = NULL;
	Node node = { 3 ,0, NULL, NULL ,NULL };  //给一个初值
	Node node1 = { 5 ,1, NULL, NULL ,NULL };
	Node node2 = { 8 ,2, NULL, NULL ,NULL };
	Node node3 = { 2 ,3, NULL, NULL ,NULL };
	Node node4 = { 6 ,4, NULL, NULL ,NULL };
	Node node5 = { 9 ,5, NULL, NULL ,NULL };
	Node node6 = { 7 ,6, NULL, NULL ,NULL };
	Node *node_d;

	CreateTree(&pTree, &node);
	AddNode(pTree, 0, &node1, left);
	AddNode(pTree, 0, &node2, right);
	AddNode(pTree, 1, &node3, left);
	AddNode(pTree, 1, &node4, right);
	AddNode(pTree, 2, &node5, left);
	AddNode(pTree, 2, &node6, right);
	PreorderPrintTree(pTree);

	//node_d = SearchNode(pTree, 3);
	//printf("index is %d ,data is %d\n", 3, node_d->data);

	printf("after delete node,");
	node_d = (Node*)malloc(sizeof(Node));
	DeleteNode(pTree, 2, node_d);
	PreorderPrintTree(pTree);

	DestroyTree(pTree);

	return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值