12、二叉树
1、二叉树的定义和初始化
//二叉树节点定义 typedef struct BinTreeNode{ ElemType data; struct BinTreeNode* leftChild; struct BinTreeNode* rightChild; }BinTreeNode; //二叉树定义 typedef struct BinTree{ BinTreeNode* root; ElemType refvalue; //结束标记 }BinTree; //初始化二叉树,并规定结束标记为 # void initBinTree(BinTree* tree,ElemType ref){ tree->root = NULL; tree->refvalue = ref; }
2、二叉树的创建方式
// 创建二叉树方式1 [node 是二级指针 C++可以通过BinTreeNode*& node引用的简便写法] void createBinTree_1(BinTree* bt,BinTreeNode** node){ ElemType item; scanf("%c",&item); if(item == bt->refvalue) *node = NULL; else{ (*node) = (BinTreeNode*) malloc(sizeof(BinTreeNode)); assert(*node != NULL); //创建根 (*node)->data = item; //递归创建 createBinTree_1(bt,&(*node)->leftChild); createBinTree_1(bt,&(*node)->rightChild); } } //创建二叉树方式2 通过返回根节点创建二叉树 BinTreeNode* createBinTree_2(BinTree* bt){ ElemType item; scanf("%c",&item); if(item == bt->refvalue) return NULL; else{ BinTreeNode* node = (BinTreeNode*) malloc(sizeof(BinTreeNode)); assert(node != NULL); node->data = item; node->leftChild = createBinTree_2(bt); node->rightChild = createBinTree_2(bt); return node; } } //创建二叉树方式3 根据字符串str创建二叉树 //此处是错误代码,原因:char* str // 1.createBinTree_3(bt,&(*node)->leftChild,++str); // 2.createBinTree_3(bt,&(*node)->rightChild,++str); // 在运行这两行代码时,如果 在运行1时又递归调用了 1 , // str不会进行改变,也就说不会"+2",在回来运行2时还是+1的状态 // 所以此处不应该char* 想要改变一级指针的值就需要二级指针 //void createBinTree_3(BinTree* bt,BinTreeNode** node,char* str){ // if(*str == bt->refvalue){ // *node = NULL; // ++str; // } else { // *node = (BinTreeNode*) malloc(sizeof(BinTreeNode)); // assert(node != NULL); // (*node)->data = *str; // //递归创建 // str++ // createBinTree_3(bt,&(*node)->leftChild,str); // createBinTree_3(bt,&(*node)->rightChild,str); // } //} //改进 ABC##DE##F##G#H## void createBinTree_3(BinTree* bt,BinTreeNode** node,char** str){ if(**str == bt->refvalue){ ++(*str); *node = NULL; } else { *node = (BinTreeNode*) malloc(sizeof(BinTreeNode)); assert(node != NULL); (*node)->data = **str; //递归创建 ++(*str); createBinTree_3(bt,&(*node)->leftChild,str); createBinTree_3(bt,&(*node)->rightChild,str); } }
3、二叉树遍历
3.1、递归方式
//先序遍历 void preOrder(BinTreeNode* node){ if(node != NULL){ printf("%c ",node->data); preOrder(node->leftChild); preOrder(node->rightChild); } } //中序遍历 void inOrder(BinTreeNode* node){ if(node != NULL){ inOrder(node->leftChild); printf("%c ",node->data); inOrder(node->rightChild); } } //后序遍历 void postOrder(BinTreeNode* node){ if(node != NULL){ postOrder(node->leftChild); postOrder(node->rightChild); printf("%c ",node->data); } }
3.2、非递归方式
//先序遍历-不采用递归 void preOrder(BinTreeNode* node){ if(node != NULL){ SeqStack st; InitStack(&st); BinTreeNode* p; //根节点入栈 push(&st,node); while(!isEmpty(&st)){ //当栈不为空 //获取栈顶 元素 GetTop(&st,&p); //出栈 Pop(&st); //访问元素 printf("%c ",p->data); if(p->rightChild != NULL) //先将右节点入栈 push(&st,p->rightChild); if(p->leftChild != NULL) //在将左节点入栈 push(&st,p->leftChild); } } } // 中序遍历 void inOrder(BinTreeNode* node){ if(node != NULL){ SeqStack st; InitStack(&st); BinTreeNode* p; //根节点入栈 push(&st,node); while(! isEmpty(&st)){ //将当前节点的左子树入栈 while(node != NULL && node->leftChild != NULL){ Push(&st,node->leftChild); node = node->leftChild; } //当访问该节点的所有左子树时 GetTop(&st,&p); Pop(&st); printf("%c ",p->data); //访问完该节点的所有左子树,将该节点的右子树入栈 if(p->rightChild != NULL){ node = p->rightChild; if(node != NULL) Push(&st,node); } } } } //后序遍历-非递归 核心思想:将该节点的左右子树都遍历完才访问该元素 //修改结构,增加标记位来记录该节点从哪边返回 typedef enum{L,R} Tag; typedef struct StkNode{ BinTreeNode* prt; Tag tag; }StkNode; void postOrder(BinTreeNode* t){ if(t != NULL){ SeqStack st; InitStack(&st); StkNode sn; BinTreeNode* p; do{ while(t != NULL){ sn.prt = t; sn.tag = L; Push(&st,sn); t = t->leftChild; } bool flag = true;//是否继续访问的标记 while(flag && !isEmpty(&st)){ GetTop(&st, &sn); Pop(&st); p = sn->prt; switch(sn.tag){ case L: //说明还没访问该节点的右子树 sn->tag = R; Push(&st,sn); flag = false;//第一次右节点,先找该右节点的左子树 t = p->rightChild; break; case R: //说明访问过右子树 printf("%c",p->data); break; } } }while(!isEmpty(&st)); } }
3.3、层次遍历