目录
1 二叉树
1.1 基本组成
数据域data
,左子树LChild
,右子树RChild
1.2 如何表示一棵树
根节点表示一棵树
1.3 二叉树的基本状态
-
空的结构体指针:表示一颗
NULL
树 -
只有根节点的二叉树:左右子树都为
NULL
-
只有左子树:右为
NULL
-
只有右子树:左为
NULL
-
左右子树都健全:满二叉树+完全二叉树
1.4 如何创建与遍历
创建一颗没有规律的二叉树
struct treeNode
{
DataType data; // 存储的数据类型
struct treeNode* LChild; // 左子树
struct treeNode* RChild; // 右子树
};
2 示例
2.1 创建
现在自己创建一棵树,有ABCDEFGK节点
// 创建树的每个节点
struct treeNode* createNode(DataType data)
{
struct treeNode* newNode = (struct treeNode*)malloc(sizeof(struct treeNode));
newNode->data = data; // 存储数据
newNode->LChild = newNode->RChild = NULL; // 左右子树都置空
return newNode;
}
struct treeNode* A = createNode('A'); // 使用上面接口创建节点A
struct treeNode* B = createNode('B');
struct treeNode* C = createNode('C');
struct treeNode* D = createNode('D');
struct treeNode* E = createNode('E');
struct treeNode* F = createNode('F');
struct treeNode* G = createNode('G');
struct treeNode* K = createNode('K');
创建完了将他们连接起来 ,很明显B,C连接在根A后,同理,D,E连接在根B后
void insertNode(struct treeNode* curNode,
struct treeNode* LchildNode, struct treeNode* RchildNode)
{
curNode->LChild = LchildNode; // 传过来的左子树设置为根的左子树
curNode->RChild = RchildNode; // 同理,右子树
}
insertNode(A, B, C); // A为根,B为左子树,C为右子树
insertNode(B, D, E); // 同理
insertNode(C, F, G);
insertNode(F, NULL, K);
2.2 遍历方法
2.2.1 递归
接口函数-中序遍历
void midOrder(struct treeNode* tree)
{
if (tree != NULL)
{
midOrder(tree->LChild); // 将根tree的 左 子树作为新根,再次进入该递归
printData(tree); // 打印根tree的数据
midOrder(tree->RChild); // 将根tree的 右 子树作为新根,再次进入该递归
}
}
若是前序遍历,则将根tree的打印提前即可
// 4. 前序遍历 函数
void preOrder(struct treeNode* tree)
{
if (tree != NULL)
{
printData(tree);
preOrder(tree->LChild);
preOrder(tree->RChild);
}
}
若是后序遍历,则将根tree的打印放后即可
// 6. 后序遍历 函数
void postOrder(struct treeNode* tree)
{
if (tree != NULL)
{
postOrder(tree->LChild);
postOrder(tree->RChild);
printData(tree);
}
}
下面使用中序遍历:
2.2.1.1 实现
创建递归函数,传根tree(A)进来
midOrder(A);
由于是中序遍历,所以首先从左子树(B)开始,再次进入遍历函数
然后,从2中左子树(D)开始,再次进入遍历函数
D作为根开始再次进入遍历函数,不过其左子树为NULL,退出遍历函数,
进入打印函数D,
而后进入右子树,又为NULL,退出D作为根的遍历函数。
进入打印函数B,
而后进入E作为根的遍历函数,
情况同D进入左子树NULL,退出,打印E,进入右子树E,NULL,
退出E作为根的遍历函数
退出后打印A,
再次进入右子树以C为根的遍历函数
过程同B,不再赘述。
结果:相同
2.2.2 栈
2.2.2.1 实现
初始化一个栈,给定大小, 栈顶设为-1(第一个元素入栈即为0,对应下标刚好0)
// 初始化一个栈,给定大小10
struct treeNode* stack[10];
int stackTop = -1; // 栈顶-1,入完第一个数据成0,刚好栈下标0开始
传 根tree(A)进入
midOrderByStack(A);
直接走左边一条路,走一个节点,将一个节点的数据存入栈,
栈顶++,并将下一个左子树赋给curNode
while (curNode)
{
stackTop++; // 栈顶+1
stack[stackTop] = curNode;// 保存每个节点到栈里
curNode = curNode->LChild;// 保存下一个左子树到curNode里,
// 以便循环进入下一个左子树
}
如果curNode为空,说明左边遍历完了,已经没有左子树
先取出最后一个节点(D)的数据,打印后,栈顶--,将右子树赋给curNode
if (stackTop != -1)
{
curNode = stack[stackTop];// 将最后一个节点出栈
printf("%c ", curNode->data);
stackTop--; // 栈顶-1
curNode = curNode->RChild;
}
2.2.2.2 完整实现
void midOrderByStack(struct treeNode* tree)
{
// 树为空
if (tree == NULL)
{
return;
}
else
{
// 初始化一个栈,给定大小10
struct treeNode* stack[10];
int stackTop = -1; // 栈顶-1,入完第一个数据成0,刚好栈下标0开始
struct treeNode* curNode = tree;
while (stackTop != -1 || curNode)
{
// 走所有的左子树
while (curNode)
{
stackTop++; // 栈顶+1
stack[stackTop] = curNode;// 保存每个节点到栈里
curNode = curNode->LChild;// 保存下一个左子树到curNode里,以便循环进入下一个左子树
}
if (stackTop != -1)
{
curNode = stack[stackTop];// 将最后一个节点出栈
printf("%c ", curNode->data);
stackTop--; // 栈顶-1
curNode = curNode->RChild;
}
}
}
}
结果: