代码
#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>
#define QUEUE_SIZE 5
//构建二叉树
typedef struct BTNode{
char element;
struct BTNode* left;
struct 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->rear + 1) % QUEUE_SIZE == paraQueuePtr->front % QUEUE_SIZE) {
printf("Error, trying to enqueue %c. queue full.\r\n", paraBTNodePtr->element);
return;
}
paraQueuePtr->nodePtrs[paraQueuePtr->rear] = paraBTNodePtr;
paraQueuePtr->rear = (paraQueuePtr->rear + 1) % QUEUE_SIZE;
printf("enqueue %c ends.\r\n", paraBTNodePtr->element);
}//Of enqueue
//从队列中删除一个元素并返回
BTNodePtr dequeue(QueuePtr paraQueuePtr){
if (isQueueEmpty(paraQueuePtr)) {
printf("Error, empty queue\r\n");
return NULL;
}
paraQueuePtr->front = (paraQueuePtr->front + 1) % QUEUE_SIZE;
//BTNodePtr tempPtr = paraQueuePtr->nodePtrs[paraQueuePtr->front + 1];
printf("dequeue %c ends.\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, tempLeftChild, tempRightChild;
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 {
tempLeftChild = constructBTNode(ch);
enqueue(tempQueuePtr, tempLeftChild);
tempParent->left = tempLeftChild;
}
//右
i ++;
ch = paraString[i];
if (ch == '#') {
tempParent->right = NULL;
} else {
tempRightChild = constructBTNode(ch);
enqueue(tempQueuePtr, tempRightChild);
tempParent->right = tempRightChild;
}
}
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("Levelwise: %s\r\n", tempString);
}
//preorder
void preorder(BTNodePtr tempPtr){
if (tempPtr == NULL){
return;
}
printf("%c", tempPtr->element);
preorder(tempPtr->left);
preorder(tempPtr->right);
}
//inorder
void inorder(BTNodePtr tempPtr){
if (tempPtr == NULL) {
return;
}
inorder(tempPtr->left);
printf("%c", tempPtr->element);
inorder(tempPtr->right);
}
//post order
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("There is only one node. Preorder visit: ");
preorder(tempHeader);
printf("\r\n");
char* tempString = "acde#bf######";
tempHeader = stringToBTree(tempString);
printf("Preorder: ");
preorder(tempHeader);
printf("\r\n");
printf("Inorder: ");
inorder(tempHeader);
printf("\r\n");
printf("Postorder: ");
postorder(tempHeader);
printf("\r\n");
printf("Levelwise: ");
levelwise(tempHeader);
printf("\r\n");
return 1;
}
运行结果
心得体会
编写二叉树的构建与遍历代码的过程中,我获得了许多宝贵的经验和心得体会。以下是我对此过程的一些总结:
-
理解数据结构:
在编写代码之前,深入理解二叉树的数据结构是至关重要的。二叉树由节点组成,每个节点最多有两个子节点,分别是左子节点和右子节点。理解这种结构是编写高效且正确代码的基础。 -
递归与迭代:
二叉树的遍历通常使用递归或迭代的方式实现。递归方法直观易懂,但可能会消耗较多的栈空间;迭代方法则更加高效,但需要额外的空间来存储节点的遍历顺序。在实现过程中,我体验到了递归和迭代各自的优势和局限性,并学会了根据具体场景选择合适的方法。 -
遍历策略:
二叉树有四种常见的遍历策略:前序遍历(根-左-右)、中序遍历(左-根-右)、后序遍历(左-右-根)和层序遍历(按层遍历)。在编写代码时,我注意到了不同遍历策略之间的区别和联系,并学会了如何根据实际需求选择合适的遍历策略。 -
边界情况处理:
在编写二叉树代码时,处理边界情况是非常重要的。例如,在遍历空树或只包含一个节点的树时,需要特别注意代码的逻辑。通过处理这些边界情况,我学会了如何编写更加健壮的代码。 -
代码的可读性和可维护性:
在编写代码时,我注重代码的可读性和可维护性。我使用了有意义的变量名和函数名,并添加了必要的注释来解释代码的功能和目的。这些做法有助于提高代码的可读性,使其他开发者更容易理解我的代码。同时,我也注重代码的可维护性,尽量避免了使用复杂的逻辑和过多的嵌套结构。 -
测试与调试:
在编写完代码后,我进行了充分的测试和调试。我使用了多种测试用例来验证代码的正确性,并使用了调试工具来跟踪代码的执行过程。通过测试和调试,我发现了代码中的错误和缺陷,并进行了相应的修改和优化。这个过程让我更加熟悉了测试和调试的重要性,并提高了我的编程能力
总之,编写二叉树的构建与遍历代码是一个充满挑战和收获的过程。通过这个过程,我不仅提高了自己的编程能力,还加深了对数据结构和算法的理解。我相信这些经验和心得体会将对我未来的学习和工作产生积极的影响。