树
基本概念
- 树是n(n>=0)个结点的有限集(n=0时称为空树)
- 非空树应该满足:
1)有且仅有一个特定的称为根的结点。
2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,…,Tm,其中每个集合本身又是一棵树,并且称为根的子树 - 树的特点
1)树的根结点没有前驱,除根结点外的所有结点有且只有一个前驱
2)树中所有结点可以有0个或多个后继
二叉树
基本概念:
1.特点:每个结点至多只有两颗子树(即二叉树中不存在度大于2的结点),并且二叉树的子树有左右之分,其次序不能任意颠倒
2. 概念:二叉树是n(n>=0)个结点的有限集合;当n=0时为空二叉树;由一个根节点和两个互不相交的被称为根的左子树和右子树组成。左右子树又分别是一颗二叉树。
3. 满二叉树:每一层结点数满足2^(层数-1)
代码实现
1.二叉树的链式存储
1.二叉树建树
2.前序遍历
前序遍历实际上就是先找到父节点写下来,然后在父节点后面写下该父节点的子结点,最后就是这个树的打印结果(大白话就是:爸爸应该领着他的两个儿子)
3.中序遍历
中序遍历就是:找到父节点然后将父节点放在中间,该父节点对应的子节点放在两边(大白话就是:父亲在中间,两个儿子在左右当护法)
4.后序遍历
后序遍历实际上就是先找到父节点,然后将父节点的子节点先写出来,最后写出父节点(大白话就是儿子先趟趟水,父亲在出来)
5.中序遍历非递归(辅助栈)
6.层次遍历(辅助队列)
#include<stdio.h>
#include<stdlib.h>
#define MaxSize 100
// 树
typedef char Elemtype;
typedef struct BiNode {
Elemtype data;
struct BiNode* lchild;
struct BiNode* rchild;
}BiNode, * BiTree;
typedef struct BLNode {
BiTree p;
struct BLNode* next;
}BLNode, * Blist;
// 栈
typedef BiTree BiElemtype;
typedef struct {
BiElemtype data[MaxSize];
int top;
}Stack;
// 初始化栈
void InitStack(Stack& S)
{
S.top = -1;
}
// 判断栈为空
bool S_IsEmpty(Stack S)
{
if (S.top == -1)
return true;
return false;
}
// 入栈
bool Push_S(Stack& S, BiElemtype e)
{
if (S.top == MaxSize - 1)
return false;
S.data[++S.top] = e;
return true;
}
// 出栈
bool Pop_S(Stack& S, BiElemtype& e)
{
if (S.top == -1)
return false;
e = S.data[S.top--];
return true;
}
// 队列
typedef struct TLNode {
BiElemtype data1;
struct TLNode* next;
}TLNode, * TList;
typedef struct {
TList front, rear;
}BQueue;
// 初始化队列
void Init_Queue(BQueue& Q)
{
Q.front = Q.rear = (TList)malloc(sizeof(TLNode));
Q.rear->next = NULL;
}
// 判断队列是否为空
bool Q_IsEmpty(BQueue Q)
{
if (Q.front == Q.rear)
return true;
return false;
}
// 入队 - 尾插法
void Q_Push(BQueue& Q, BiElemtype e)
{
TList p = (TList)malloc(sizeof(TLNode));
p->data1 = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
}
// 出队 - 头部删除
bool Q_Pop(BQueue& Q, BiElemtype& e)
{
if (Q.front == Q.rear)
return false;
TList p = Q.front->next;
e = p->data1;
Q.front->next = p->next;
if (p == Q.rear)
Q.rear = Q.front;
free(p);
p = NULL;
return true;
}
// 前序遍历
void PreOrder(BiTree tree)
{
if (tree != NULL)
{
putchar(tree->data);
PreOrder(tree->lchild);
PreOrder(tree->rchild);
}
}
// 中序遍历
void InOrder(BiTree tree)
{
if (tree != NULL)
{
InOrder(tree->lchild);
putchar(tree->data);
InOrder(tree->rchild);
}
}
// 后序遍历
void PosOrder(BiTree tree)
{
if (tree != NULL)
{
PosOrder(tree->lchild);
PosOrder(tree->rchild);
putchar(tree->data);
}
}
// 中序遍历非递归
void InOrder2(BiTree tree)
{
Stack S;
InitStack(S);
BiTree T = tree;
while (T || !S_IsEmpty(S))
{
if (T)
{
Push_S(S, T);
T = T->lchild;
}
else
{
Pop_S(S, T);
putchar(T->data);
T = T->rchild;
}
}
}
// 层次遍历(广度优先遍历)
void LevelOrder(BiTree tree)
{
BQueue Q;
Init_Queue(Q);
BiTree T = tree;
Q_Push(Q, T); // 入队树根
while (!Q_IsEmpty(Q))
{
Q_Pop(Q, T);
putchar(T->data);
if (T->lchild != NULL)
Q_Push(Q, T->lchild);
if (T->rchild != NULL)
Q_Push(Q, T->rchild);
}
}
int main(void)
{
BiTree tree = NULL; // 树根
BiTree pnew;
char c;
Blist phead = NULL, ptail = NULL, plist = NULL, pcur = NULL;
while (scanf("%c", &c) != EOF)
{
if (c == '\n')
break;
pnew = (BiTree)calloc(1, sizeof(BiNode));
pnew->data = c;
plist = (Blist)calloc(1, sizeof(BLNode));
plist->p = pnew;
if (tree == NULL)
{
tree = pnew;
phead = plist;
ptail = plist;
pcur = plist;
continue;
}
else {
ptail->next = plist;
ptail = plist;
}
if (pcur->p->lchild == NULL)
pcur->p->lchild = pnew;
else if (pcur->p->rchild == NULL)
{
pcur->p->rchild = pnew;
pcur = pcur->next;
}
}
printf("--------前序遍历--------\n");
PreOrder(tree);
printf("\n--------中序遍历--------\n");
InOrder(tree);
printf("\n--------后序遍历--------\n");
PosOrder(tree);
printf("\n--------中序遍历非递归--------\n");
InOrder2(tree);
printf("\n--------层次遍历--------\n");
LevelOrder(tree);
return 0;
}
写在最后:这部分代码有些长,需要耐下性子来读,中序遍历非递归以及层次遍历,我就不用图来表达了,大家可以自己用笔画一画,并不是很难,加油!