由于二叉树的每个结点具有一定的先后顺序,其作用是很大的。关于二叉树的构造这里是结合队列来完成的。首先分配一个指针队列,使用指针队列是由于其先进先出的特点,这些指针的类型是和二叉树结点的类型是一致的,用于保存结点的地址。当我们逐个扫描数据时,将数据与两个指针域构造成一个结点,队列每出队一个,就读取两个数据(将这两个数据作为出队那个数据的左右Child),并将这两个数据的地址传入队列中,等待出队迎接它们各自的Children。如图:
代码步骤
创建二叉树结点
//二叉树结点
typedef struct BTreeNode{
BTreeNode *left;
BTreeNode *right;
char data;
}*BTreeNodePtr;
创建指针队列
//一个包含多个指针的队列
typedef struct Queue{
int front;
int rear;
BTreeNodePtr *nodePtrs;
}*QueuePtr;
队列初始化
//初始化队列
QueuePtr initQueue(){
QueuePtr resultPtr = (QueuePtr)malloc(sizeof(struct Queue));
resultPtr->front = 0;
resultPtr->rear = 1;
resultPtr->nodePtrs = (BTreeNodePtr*)malloc(sizeof(BTreeNodePtr)*Max);
return resultPtr;
}
将数据构造成一个二叉树节点
BTreeNodePtr constructBTNode(char paraChar){
BTreeNodePtr resultPtr = (BTreeNodePtr)malloc(sizeof(struct BTreeNode));
resultPtr->data = paraChar;
resultPtr->left = NULL;
resultPtr->right = NULL;
return resultPtr;
}
入队
//添加一个队列中的指针,指向新节点
void enqueue(QueuePtr paraPtr,BTreeNodePtr paraBTNode){
printf("front = %d, rear = %d.\r\n", paraPtr->front, paraPtr->rear);
if((paraPtr->rear + 1)%Max == paraPtr->front%Max){
printf("错误,尝试插入%c,队已满\n",paraBTNode->data);
return ;
}
paraPtr->nodePtrs[paraPtr->rear] = paraBTNode;
paraPtr->rear = (paraPtr->rear +1)%Max;
printf("%c入队结束\n",paraBTNode->data);
return;
}
出队并返回
BTreeNodePtr dequeue(QueuePtr paraPtr){
if(isQueueEmpty(paraPtr)){
printf("队列为空\n");
return NULL;
}
paraPtr->front = (paraPtr->front + 1)%Max;
printf("%c删除并返回结束\r\n", paraPtr->nodePtrs[paraPtr->front]->data);
return paraPtr->nodePtrs[paraPtr->front];
}
判断队列是否为空
//判断队列 是否为空
bool isQueueEmpty(QueuePtr paraPtr){
if((paraPtr->front +1)%Max == paraPtr->rear%Max){
return true;
}
return false;
}
构建二叉树
BTreeNodePtr stringToBTree(char *paraString){
int i;
char ch;
QueuePtr tempQueuePtr = initQueue();//使用队列来管理指针
BTreeNodePtr resultHeader;
BTreeNodePtr tempParent, tempLeftChild, tempRightChild;
i = 0;
ch = paraString[i];
resultHeader = constructBTNode(ch);
enqueue(tempQueuePtr,resultHeader);
//连接二叉树左右child
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(BTreeNodePtr paraTreePtr){
char string[100];
int i = 0;
QueuePtr tempQueuePtr = initQueue();
BTreeNodePtr tempNodePtr;
enqueue(tempQueuePtr,paraTreePtr);
while(!isQueueEmpty(tempQueuePtr)){
tempNodePtr = dequeue(tempQueuePtr);
string[i] = tempNodePtr->data;
i++;
if(tempNodePtr->left != NULL){
enqueue(tempQueuePtr,tempNodePtr->left);
}
if(tempNodePtr->right != NULL){
enqueue(tempQueuePtr,tempNodePtr->right);
}
}
string[i]='\0';
printf("Levelwise:%s",string);
}
前,中,后序遍历,这里采用递归的算法
//前序遍历
void preorder(BTreeNodePtr paraNodePtr){
if(paraNodePtr == NULL){
return;
}
printf("%c",paraNodePtr->data);
preorder(paraNodePtr->left);
preorder(paraNodePtr->right);
}
//中序遍历
void Inorder(BTreeNodePtr paraNodePtr){
if(paraNodePtr == NULL){
return;
}
Inorder(paraNodePtr->left);
printf("%c",paraNodePtr->data);
Inorder(paraNodePtr->right);
}
//后序遍历
void postorder(BTreeNodePtr paraNodePtr){
if(paraNodePtr == NULL){
return;
}
postorder(paraNodePtr->left);
postorder(paraNodePtr->right);
printf("%c",paraNodePtr->data);
}
代码入口
int main(){
BTreeNodePtr 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;
}