摘要:二叉树不是人脑固有的东西=-=
一、树及二叉树定义
树是由n
个结点组成的有限集合T;
二叉树是每个结点最多有两个子树的有序树;
二叉树不是树的特殊情形。
1、二叉树的链式存储结构
图a为最常用的二叉链表法。
2、几种遍历
(1)、先序遍历(DLR):从一棵二叉树根节点为起点,沿着二叉树外沿,逆时针走一圈回到根节点,路上遇到的元素顺序,就是先序遍历的结果。
(2)、中序遍历(LDR):可以理解为每个节点从最左边开始垂直掉到地上,然后从左往右数,得出的结果便是中序遍历的结果。
(3)、后序遍历(LRD):可以看成剪树叶,绕树一圈,如果发现一剪刀能剪下来的树叶(必须为一个树叶,及树叶一个个下来,不能一串下来),就把它剪下来,组成的就是后序遍历了。
(4)、层次遍历:对整个二叉树按从上到下,对每一层从左到右的顺序进行遍历(类似于队列的先进先出)。
二、二叉树的操作
1、结构体定义
//二叉树结点
typedef struct BTNode
{
char element;
BTNode* left;
BTNode* right;
} BTNode,*BTNodePtr;
//带有多个指针的队列
typedef struct BTNodePtrQueue
{
BTNodePtr* nodePtrs;
int front;
int rear;
} BTNodePtrQueue,*QueuePtr;
2、初始化队列
//初始化队列
QueuePtr initQueue()
{
QueuePtr resultQueuePtr = (QueuePtr)malloc(sizeof(struct BTNodePtrQueue));
resultQueuePtr->nodePtrs = (BTNodePtr*)malloc(QUEUE_SIZE * sizeof(BTNodePtr));
resultQueuePtr->front = 0;
resultQueuePtr->rear = 1;
return resultQueuePtr;
}
3、判断队列是否为空
//判断队列是否为空
bool isQueueEmpty(QueuePtr paraQueuePtr)
{
if((paraQueuePtr->front + 1)% QUEUE_SIZE == paraQueuePtr->rear)
{
return true;
}
return false;
}
4、入队
//添加指向队列的指针
void enqueue(QueuePtr paraQueuePtr,BTNodePtr paraBTNodePtr)
{
printf("front = %d, rear = %d.\r\n",paraQueuePtr->front,paraQueuePtr->rear);
if((paraQueuePtr->front + 1)% QUEUE_SIZE == paraQueuePtr->front % QUEUE_SIZE)
{
printf("错误,队列已满,无法加入%c.\r\n",paraBTNodePtr->element);
return;
}
paraQueuePtr->nodePtrs[paraQueuePtr->rear] = paraBTNodePtr;
paraQueuePtr->rear = (paraQueuePtr->rear + 1) % QUEUE_SIZE;
printf("入队 %c,结束.\r\n",paraBTNodePtr->element);
}
5、出队
//从队列中移除一个元素并返回
BTNodePtr dequeue(QueuePtr paraQueuePtr)
{
if(isQueueEmpty(paraQueuePtr))
{
printf("错误,队列为空.\r\n");
return NULL;
}
paraQueuePtr->front = (paraQueuePtr->front + 1) % QUEUE_SIZE;
printf("出队 %c.\r\n",paraQueuePtr->nodePtrs[paraQueuePtr->front]->element);
return paraQueuePtr->nodePtrs[paraQueuePtr->front] ;
}
6、构造结点
//构造一个结点
BTNodePtr constructBTNode(char paraChar)
{
BTNodePtr resultPtr = (BTNodePtr)malloc(sizeof(BTNode));
resultPtr->element = paraChar;
resultPtr->left = NULL;
resultPtr->right = NULL;
return resultPtr;
}
7、核心函数将字符串构造二叉树
//使用给定的字符串构造二叉树
BTNodePtr stringToBTree(char* paraString)
{
int i;
char ch;
//使用队列管理指针
QueuePtr tempQueuePtr = initQueue();
BTNodePtr resultHeader;
BTNodePtr tempParent,tempLeft,tempRight;
i=0;
ch = paraString[i];
resultHeader = constructBTNode(ch);
enqueue(tempQueuePtr,resultHeader);
while(!isQueueEmpty(tempQueuePtr))
{
tempParent = dequeue(tempQueuePtr);
//左子树
i++;
ch = paraString[i] ;
if(ch == '#')
{
tempParent->left = NULL;
}
else
{
tempLeft = constructBTNode(ch);
enqueue(tempQueuePtr,tempLeft);
tempParent->left = tempLeft;
}
//右子树
i++;
ch = paraString[i] ;
if(ch == '#')
{
tempParent->right = NULL;
}
else
{
tempRight = constructBTNode(ch);
enqueue(tempQueuePtr,tempRight);
tempParent->right = tempRight;
}
}
return resultHeader;
}
8、4种遍历方式
//层序遍历
void levelwise(BTNodePtr paraTreePtr)
{
//使用队列管理指针
char tempString[100];
int i = 0;
QueuePtr tempQueuePtr = initQueue();
BTNodePtr tempNodePtr;
enqueue(tempQueuePtr,paraTreePtr);
while(!isQueueEmpty(tempQueuePtr))
{
tempNodePtr = dequeue(tempQueuePtr);
//输出
tempString[i] = tempNodePtr->element;
i++;
if(tempNodePtr->left != NULL)
{
enqueue(tempQueuePtr,tempNodePtr->left);
}
if(tempNodePtr->right != NULL)
{
enqueue(tempQueuePtr,tempNodePtr->right);
}
}
tempString[i] = '\0';
printf("层序遍历:%s\r\n",tempString);
}
//前序遍历
void preorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL);
{
return;
}
printf("%c",tempPtr->element);
preorder(tempPtr->left);
preorder(tempPtr->right);
}
//中序遍历
void inorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
inorder(tempPtr->left);
printf("%c",tempPtr->element);
inorder(tempPtr->right);
}
//后序遍历
void postorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
postorder(tempPtr->left);
postorder(tempPtr->right);
printf("%c",tempPtr->element);
}
总代码
#include<stdio.h>
#include<malloc.h>
#define QUEUE_SIZE 5
//二叉树结点
typedef struct BTNode
{
char element;
BTNode* left;
BTNode* right;
} BTNode,*BTNodePtr;
//带有多个指针的队列
typedef struct BTNodePtrQueue
{
BTNodePtr* nodePtrs;
int front;
int rear;
} BTNodePtrQueue,*QueuePtr;
//初始化队列
QueuePtr initQueue()
{
QueuePtr resultQueuePtr = (QueuePtr)malloc(sizeof(struct BTNodePtrQueue));
resultQueuePtr->nodePtrs = (BTNodePtr*)malloc(QUEUE_SIZE * sizeof(BTNodePtr));
resultQueuePtr->front = 0;
resultQueuePtr->rear = 1;
return resultQueuePtr;
}
//判断队列是否为空
bool isQueueEmpty(QueuePtr paraQueuePtr)
{
if((paraQueuePtr->front + 1)% QUEUE_SIZE == paraQueuePtr->rear)
{
return true;
}
return false;
}
//添加指向队列的指针
void enqueue(QueuePtr paraQueuePtr,BTNodePtr paraBTNodePtr)
{
printf("front = %d, rear = %d.\r\n",paraQueuePtr->front,paraQueuePtr->rear);
if((paraQueuePtr->front + 1)% QUEUE_SIZE == paraQueuePtr->front % QUEUE_SIZE)
{
printf("错误,队列已满,无法加入%c.\r\n",paraBTNodePtr->element);
return;
}
paraQueuePtr->nodePtrs[paraQueuePtr->rear] = paraBTNodePtr;
paraQueuePtr->rear = (paraQueuePtr->rear + 1) % QUEUE_SIZE;
printf("入队 %c,结束.\r\n",paraBTNodePtr->element);
}
//从队列中移除一个元素并返回
BTNodePtr dequeue(QueuePtr paraQueuePtr)
{
if(isQueueEmpty(paraQueuePtr))
{
printf("错误,队列为空.\r\n");
return NULL;
}
paraQueuePtr->front = (paraQueuePtr->front + 1) % QUEUE_SIZE;
printf("出队 %c.\r\n",paraQueuePtr->nodePtrs[paraQueuePtr->front]->element);
return paraQueuePtr->nodePtrs[paraQueuePtr->front] ;
}
//构造一个结点
BTNodePtr constructBTNode(char paraChar)
{
BTNodePtr resultPtr = (BTNodePtr)malloc(sizeof(BTNode));
resultPtr->element = paraChar;
resultPtr->left = NULL;
resultPtr->right = NULL;
return resultPtr;
}
//使用给定的字符串构造二叉树
BTNodePtr stringToBTree(char* paraString)
{
int i;
char ch;
//使用队列管理指针
QueuePtr tempQueuePtr = initQueue();
BTNodePtr resultHeader;
BTNodePtr tempParent,tempLeft,tempRight;
i=0;
ch = paraString[i];
resultHeader = constructBTNode(ch);
enqueue(tempQueuePtr,resultHeader);
while(!isQueueEmpty(tempQueuePtr))
{
tempParent = dequeue(tempQueuePtr);
//左子树
i++;
ch = paraString[i] ;
if(ch == '#')
{
tempParent->left = NULL;
}
else
{
tempLeft = constructBTNode(ch);
enqueue(tempQueuePtr,tempLeft);
tempParent->left = tempLeft;
}
//右子树
i++;
ch = paraString[i] ;
if(ch == '#')
{
tempParent->right = NULL;
}
else
{
tempRight = constructBTNode(ch);
enqueue(tempQueuePtr,tempRight);
tempParent->right = tempRight;
}
}
return resultHeader;
}
//层序遍历
void levelwise(BTNodePtr paraTreePtr)
{
//使用队列管理指针
char tempString[100];
int i = 0;
QueuePtr tempQueuePtr = initQueue();
BTNodePtr tempNodePtr;
enqueue(tempQueuePtr,paraTreePtr);
while(!isQueueEmpty(tempQueuePtr))
{
tempNodePtr = dequeue(tempQueuePtr);
//输出
tempString[i] = tempNodePtr->element;
i++;
if(tempNodePtr->left != NULL)
{
enqueue(tempQueuePtr,tempNodePtr->left);
}
if(tempNodePtr->right != NULL)
{
enqueue(tempQueuePtr,tempNodePtr->right);
}
}
tempString[i] = '\0';
printf("层序遍历:%s\r\n",tempString);
}
//前序遍历
void preorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL);
{
return;
}
printf("%c",tempPtr->element);
preorder(tempPtr->left);
preorder(tempPtr->right);
}
//中序遍历
void inorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
inorder(tempPtr->left);
printf("%c",tempPtr->element);
inorder(tempPtr->right);
}
//后序遍历
void postorder(BTNodePtr tempPtr)
{
if(tempPtr == NULL)
{
return ;
}
postorder(tempPtr->left);
postorder(tempPtr->right);
printf("%c",tempPtr->element);
}
int main()
{
BTNodePtr tempHeader;
tempHeader = constructBTNode('c');
printf("只有一个结点时,先序遍历:");
preorder(tempHeader);
printf("\r\n");
char* tempString = "lty#yy#ds######";
tempHeader = stringToBTree(tempString);
printf("先序遍历:");
preorder(tempHeader);
printf("\r\n");
printf("中序遍历:");
inorder(tempHeader);
printf("\r\n");
printf("后序遍历:");
postorder(tempHeader);
printf("\r\n");
printf("层序遍历:");
levelwise(tempHeader);
printf("\r\n");
return 1;
}
结果展示
先序遍历:
中序遍历:tdyslyy
后序遍历:dsytyyl
层序遍历:front = 0, rear = 1.
入队 l,结束.
出队 l.
front = 1, rear = 2.
入队 t,结束.
front = 1, rear = 3.
入队 y,结束.
出队 t.
front = 2, rear = 4.
入队 y,结束.
出队 y.
front = 3, rear = 0.
入队 y,结束.
出队 y.
front = 4, rear = 1.
入队 d,结束.
front = 4, rear = 2.
入队 s,结束.
出队 y.
出队 d.
出队 s.
层序遍历:ltyyyds