二叉树基本操作(头文件): //二叉树的创建 void CreateBiTree(BTNode **root) ///二级指针作为函数参数 { ///void CreateBiTree(BiTree &root) //引用类型的参数 char ch; ///要插入的数据 scanf("\n%c", &ch); ///cin>>ch; if(ch=='#') ///BiTree *CreateBiTree() //返回结点指针类型 *root = NULL; else { *root = (BTNode *)malloc(sizeof(BTNode)); (*root)->data = ch; CreateBiTree(&((*root)->lchild)); CreateBiTree(&((*root)->rchild)); } } void Pre_order_Creat_Btree(BTree *root) //仿先序遍历创建二叉树 { DataType c; if((c=getchar())=='#') *root=NULL; else { *root=(BTNode *)malloc(sizeof(BTNode)); (*root)->data=c; //别以为把这行代码换下位置就成了中、后序遍历创建方式,肯定是错误的 Pre_order_Creat_Btree(&((*root)->lchild)); Pre_order_Creat_Btree(&((*root)->rchild)); } } //我们首先创建的是根节点,先序首先操作的是根节点我们才能固定出一棵二叉树,中后序首先操作不是根节点, //二叉树遍历递归算法 //-----------------------------先序遍历递归版--------------------------------- void Pre_order_Rec(BTree root) { if(root) { printf("%c ",root->data); Pre_order_Rec(root->lchild); Pre_order_Rec(root->rchild); } } //-----------------------------中序遍历递归版---------------------------------- void In_order_Rec(BTree root) { if(root) { In_order_Rec(root->lchild); printf("%c ",root->data); In_order_Rec(root->rchild); } } //------------------------------后序遍历递归版----------------------------------- void Post_order_Rec(BTree root) { if(root) { Post_order_Rec(root->lchild); Post_order_Rec(root->rchild); printf("%c ",root->data); } } //访问函数,可以定义声明作为函数指针使用 int visit(BTree Tree) { if(Tree) { printf("%c ",Tree->data); //访问节点函数 return 1; } else return 0; } //层次遍历非递归算法 //------------------------------方法一C++STL实现--------------------------- void LevelOrder_First(BTree Tree) { queue<BTree>Q; BTree p; p=Tree; if(visit(p)==1) //只要当前的这棵树不为空,就访问该树根节点的信息并进行入队操作 Q.push(p); while(!Q.empty()) //层次遍历利用了先进先出的性质,故想到了队列 { p=Q.front(); Q.pop(); if(visit(p->lchild)==1) Q.push(p->lchild); if(visit(p->rchild)==1) Q.push(p->rchild); } } //-------------------------------方法二C语言实现-------------------------- void LevelOrder_Second(BTree Tree) { BTNode *queue[1000]; //定义队列有十个空间 --- 这种方式可以说根本就没有用到队列,充其量只是思维上和队列一致 if(Tree==NULL) //空树则返回 //很方便---我喜欢 return; int front,rear; front=rear=0; queue[rear++]=Tree; while(front!=rear) //如果队尾指针不等于对头指针时 { cout<<queue[front]->data<<" "; //输出遍历结果 if(queue[front]->lchild!=NULL) //将队首结点的左孩子指针入队列 { queue[rear]=queue[front]->lchild; rear++; //队尾指针后移一位 } if(queue[front]->rchild!=NULL) { queue[rear]=queue[front]->rchild; //将队首结点的右孩子指针入队列 rear++; //队尾指针后移一位 } front++; //对头指针后移一位 } } //---------------------------------方法三-课本版----------------------------------- void LevelOrder_Third(BTree root) { Squeue queue; BTNode *p=NULL; if(NULL!=root) { p=root; Init_Squeue(queue); En_Squeue(queue,p); while(!Empty_Squeue(*queue)) { De_Squeue(queue,&p); printf("%c ",p->data); if(p->lchild!=NULL) En_Squeue(queue,p->lchild); if(p->rchild!=NULL) En_Squeue(queue,p->rchild); } } } //计算二叉树的深度-递归版 //------------------------------------方法一-------------------------- int BTree_Depth_First(BTree root) { if(root) { int h1=BTree_Depth_First(root->lchild); int h2=BTree_Depth_First(root->rchild); return (h1>h2?h1:h2)+1; } //return (depth(T->lchild)>depth(T->rchild)?depth(T->lchild):depth(T->rchild))+1; return 0; } //-----------------------------------方法二---------------------------- void BTree_Depth_Second(BTree root,int Count,int &depth) { if(root) { if(Count>depth) depth=Count; BTree_Depth_Second(root->lchild,Count+1,depth); BTree_Depth_Second(root->rchild,Count+1,depth); } } //计算二叉树的叶子节点数 void BTree_leave_num(BTree root,int &Count) { if(root) //这里你为什么要用引用。1、你没有返回值。2、实参到形参的传递只是赋值过程不改变原值 3、你也没用指针 { if(!root->lchild&&!root->rchild) //不改变二叉树的结构,我不应该用指针的 Count++; BTree_leave_num(root->lchild,Count); BTree_leave_num(root->rchild,Count); } } //先中后二叉树遍历非递归版 //---------------------------先序遍历非递归算法---------------------- typedef BTree Elemtype; void PreOrder_NonRec_First(BTree root) { SqStack stack; StackInitiate(&stack); BTNode *p=NULL; if(root!=NULL) { stack.data[++stack.top]=root; while(stack.top>0) { p=stack.data[stack.top--]; printf("%c ",p->data); if(NULL!=p->rchild) stack.data[++stack.top]=p->rchild; if(NULL!=p->lchild) stack.data[++stack.top]=p->lchild; } } } void PreOrder_NonRec_Second(BTree Tree) //先序遍历的非递归 { if(!Tree) return ; stack<BTree>s; s.push(Tree); while(!s.empty()) { BTree temp=s.top(); //总结:关于先中后遍历的栈如何应用,你只需要根据先中后序访问顺序关系知道什么时候做出栈,什么时候做入栈 cout<<temp->data<<" "; //然后判断出栈或者入栈的时候需不需要进行访问操作就明白了 s.pop(); if(temp->rchild) //这种和下面的两种有所不同,请读者自己体会 s.push(temp->rchild); if(temp->lchild) s.push(temp->lchild); } } void PreOrder_NonRec_Third(BTree Tree) //先序遍历的非递归---法一:只在入栈的时候做访问操作 { if(!Tree) return ; stack<BTree>s; BTree curr=Tree; while(curr!=NULL||!s.empty()) { while(curr!=NULL) //根据先序的关系知先让最左边的孩子全部入栈(边入栈边访问),完后作出栈就好了再重复入栈就好了 { cout<<curr->data<<" "; s.push(curr); curr=curr->lchild; } if(!s.empty()) { curr=s.top(); s.pop(); curr=curr->rchild; } } } void PreOrder_NonRec_Fouth(BTree Tree) //先序遍历的非递归 { if(!Tree) return ; stack<BTree> s; while(Tree) //左子树上的节点全部压入到栈中 { s.push(Tree); cout<<Tree->data<<" "; Tree=Tree->lchild; } while(!s.empty()) { BTree temp=s.top()->rchild; // 栈顶元素的右子树 s.pop(); // 弹出栈顶元素 while(temp) //栈顶元素存在右子树,则对右子树同样遍历到最下方 { cout<<temp->data<<" "; s.push(temp); //这里也是在入栈的时候做访问操作(因为先序首先访问的就是每一棵树的根节点) temp=temp->lchild; } } } //-----------------------中序遍历非递归算法------------------------ void InOrder_NonRec_First(BTree root) { SqStack stack; BTNode *p=NULL; StackInitiate(&stack); p=root; while(NULL!=p||stack.top>0) { while(NULL!=p) { stack.data[++stack.top]=p; p=p->lchild; } p=stack.data[stack.top--]; printf("%c ",p->data); p=p->rchild; } } void InOrder_NonRec_Second(BTree T) //中序遍历的非递归 { if(!T) return ; BTree curr=T; //指向当前要检查的节点 stack<BTree>s; while(curr!=NULL||!s.empty()) { while(curr!=NULL) { s.push(curr); curr=curr->lchild; } if(!s.empty()) //中序遍历首先访问的是左节点再是根节点,所以是在出栈的时候做访问操作 { //同时入栈的左节点又充当根节点的作用 curr=s.top(); s.pop(); cout<<curr->data<<" "; curr=curr->rchild; } } } void InOrder_NonRec_Third(BTree T) //中序遍历的非递归 { if(!T) return ; stack<BTree>s; BTree curr=T->lchild; //指向当前要检查的节点 s.push(T); while(curr!=NULL||!s.empty()) { while(curr!=NULL) //一直向左走 { s.push(curr); curr=curr->lchild; } curr=s.top(); //还是入栈的时候不做访问操作,只在出栈的时候做访问操作 s.pop(); cout<<curr->data<<" "; curr = curr->rchild; } } void PostOrder_NonRec_Second(BTree T) //后序遍历的非递归 { stack<BTree>S; BTree curr=T; //指向当前要检查的节点 BTree previsited=NULL; //指向前一个被访问的节点 while(curr!=NULL||!S.empty()) //栈空时结束 { while(curr!=NULL) //一直向左走直到为空 { S.push(curr); curr=curr->lchild; } curr=S.top(); // 当前节点的右孩子如果为空或者已经被访问,则访问当前节点 if(curr->rchild==NULL||curr->rchild==previsited) { cout<<curr->data<<" "; //这个思路很好,相比课本上的,显得精简活跃,当你无法具体理解代码时,你就画出一棵二叉树再对比代码的思路进行 previsited=curr; //一步一步地跟踪 S.pop(); curr = NULL; } else curr=curr->rchild; // 否则访问右孩子 } } void PostOrder_NonRec_Third(BTree T) //后序遍历的非递归 双栈法 { stack<BTree>s1,s2; BTree curr; //指向当前要检查的节点 s1.push(T); while(!s1.empty()) //栈空时结束 { curr=s1.top(); s1.pop(); s2.push(curr); if(curr->lchild) //这个方式就更加简单了,具有实际效率 s1.push(curr->lchild); if(curr->rchild) s1.push(curr->rchild); } while(!s2.empty()) { printf("%c ", s2.top()->data); s2.pop(); } } //查找指定节点的孩子的算法 void Find_Child_Bnode(BTNode *p,BTNode **p_lchild,BTNode **p_rchild) { if(p==NULL) return ; *p_lchild=p->lchild; *p_rchild=p->rchild; return ; } //查找指定节点的双亲的算法 typedef BTree Elemtype; int Find_Parent_Bnode(BTree root,BTNode *p,BTNode **p_parent) { SqStack stack; BTNode *q=NULL; *p_parent=NULL; if(p==root) return 0; stack.top=0;q=root; while(NULL!=q||stack.top>0) { while(NULL!=q) { stack.data[++stack.top]=q; q=q->lchild; } q=stack.data[stack.top--]; if(p==q->lchild||p==q->rchild) { *p_parent=q; //二叉树中一个节点最多只有一个父节点,别以为叫双亲你就以为是两个 return 1; } q=q->rchild; } return 0; } //查找指点节点子孙节点的算法 typedef char DataType; typedef BTree Elemtype; void FindDescendants_Blist(BTNode *p) { SqQueue queue; //队列的声明与定义 BTNode *q=NULL;int count=0; if(p==NULL) { printf("当前输入的节点参数有错!!!\n"); return ; } if(p->lchild==NULL&&p->rchild==NULL) { printf("当前输入的节点是叶子节点,无孩子节点!!!\n"); return ; } queue.front=0; queue.rear=0; printf("%c节点的所有子孙节点如下所示:\n",p->data); queue.data[queue.rear]=p; queue.rear=(queue.rear+1)%MAX; while(queue.front!=queue.rear) { q=queue.data[queue.front]; queue.front=(queue.front+1)%MAX; if(q!=p) { printf("%c ",q->data); count++; if(count==5) printf("\n"); } if(NULL!=q->lchild) { queue.data[queue.rear]=q->lchild; queue.rear=(queue.rear+1)%MAX; } if(NULL!=q->rchild) { queue.data[queue.rear]=q->rchild; queue.rear=(queue.rear+1)%MAX; } } printf("\n"); printf("节点%c共有%d个子孙节点.\n",p->data,count); return ; } //查找指定节点祖先的算法 void FindAncersors_Blist(BTree root,BTNode *p) //这样子的所有祖先连起来就是折线(为什么这么说,想过吗) { BTNode *p_parent=p; BTNode *q=NULL; if(p==root) { printf("输入的节点信息是根节点,无祖先可寻!!!\n"); return ; } while(p_parent!=root) { q=p_parent; p_parent=NULL; Find_Parent_Bnode(root,q,&p_parent); printf("节点%c是节点%c的一个祖先节点.\n",p_parent->data,p->data); } } //基于后序遍历的二叉树各类结点统计递归算法 int count_leaf=0; int count_onedegree=0; int count_twodegree=0; void NodeCount_Rec(BTree root) { if(root!=NULL) { NodeCount_Rec(root->lchild); NodeCount_Rec(root->rchild); if(NULL==root->lchild&&NULL==root->rchild) count_leaf++; else if(NULL!=root->lchild&&NULL!=root->rchild) count_twodegree++; else count_onedegree++; } } //给某节点插入左节点 BTree Insert_LeftNode(BTree father,DataType x) { BTree p=NULL,q=NULL; if(father==NULL) return NULL; //注意在函数调用时NULL和0的区别(返回值的类型) q=father->lchild; p=(BTNode *)malloc(sizeof(BTNode)); p->data=x; p->lchild=q; p->rchild=NULL; father->lchild=p; return father->lchild; } //给某节点插入右节点 BTree Insert_RightNode(BTree father,DataType x) { BTree p=NULL,q=NULL; if(father==NULL) return NULL; q=father->rchild; p=(BTree)malloc(sizeof(BTNode)); p->data=x; p->rchild=q; p->lchild=NULL; father->rchild=p; return father->rchild; } //通过释放节点达到销毁的目的 void Destroy_BTree(BTree *root) { if((*root)!=NULL&&(*root)->lchild!=NULL) Destroy_BTree(&(*root)->lchild); if((*root)!=NULL&&(*root)->rchild!=NULL) Destroy_BTree(&(*root)->rchild); free(*root); //这里有个BUG } //删除左子树 BTree Delete_LeftTree(BTree Node) { if(NULL==Node->lchild&&NULL==Node->rchild) //若要删除的为叶子节点则不删除 return NULL; Destroy_BTree(&Node->lchild); //删除该节点的左子树 Node->lchild=NULL; return Node; } //删除右子树 BTree Delete_RightTree(BTree Node) { if(NULL==Node->lchild&&NULL==Node->rchild) ////若要删除的为叶子节点则不删除 return NULL; Destroy_BTree(&Node->rchild); //删除该节点的右子树 Node->rchild=NULL; return Node; } //交换所有节点的左右子树 void Exchange_BTree(BTree root) { if(root!=NULL) { Exchange_BTree(root->lchild); Exchange_BTree(root->rchild); //首先不断的递归到最底层的二叉树,然后再不断的往上交换 BTree p=root->lchild; root->lchild=root->rchild; root->rchild=p; } } void PreOrder(BTree root) //输出后序遍历的逆序序列---想想这样为什么就解决了这个问题 { if(root) { printf("%f",root->data); PreOrder(root->rchild); PreOrder(root->lchild); } } //查找节点函数 int Insearch_BTree(BTree root,DataType x,BTree &p) { if(!root) { p=NULL; return 0; } else { if(root->data==x) { printf("元素已找到,正在返回!!!\n"); p=root; return 1; } if(Insearch_BTree(root->lchild,x,p)) //只要是棵二叉树(只有两个方向),这左右(方向)递归函数一起使用就能遍历整个二叉树 return 1; else return Insearch_BTree(root->rchild,x,p); } return 0; } void Delay(char *p) //延时函数的定义 { while(1) { if(*p!=0) printf("%c",*p++); else break; Sleep(10); //延时控制间断语句 } } //有w存在时就表示要新建一个文件,其他情况都不会新建 void Basic_operation(BTree root) //功能函数 { int n; char ch;BTree head,arrow,p_lchild,p_rchild; int count=0,depth=1; system("cls"); printf("\t\t\t\t\t\t\t\t----------------------------------------------------\n"); printf("\t\t\t\t\t\t\t\t+ 二叉树基本操作 +\n"); printf("\t\t\t\t\t\t\t\t----------------------------------------------------\n"); printf("\t\t\t\t\t\t\t\t\t*************************************\n"); printf("\t\t\t\t\t\t\t\t |\t 1、创建二叉树 |\n"); printf("\t\t\t\t\t\t\t\t |\t 2、插入左孩子 |\n"); //为什么不能在这里定义head指针---因为每次调用功能函数后,head指针又被重新初始化了 printf("\t\t\t\t\t\t\t\t |\t 3、插入右孩子 |\n"); printf("\t\t\t\t\t\t\t\t |\t 4、查找某节点 |\n"); printf("\t\t\t\t\t\t\t\t |\t 5、求叶子数目 |\n"); printf("\t\t\t\t\t\t\t\t |\t 6、求深度操作 |\n"); printf("\t\t\t\t\t\t\t\t |\t 7、先中后递归打印 |\n"); printf("\t\t\t\t\t\t\t\t |\t 8、先中后非递归打印 |\n"); printf("\t\t\t\t\t\t\t\t |\t 9、层次遍历 |\n"); printf("\t\t\t\t\t\t\t\t |\t 10、各类节点数 |\n"); printf("\t\t\t\t\t\t\t\t |\t 11、树左右互换 |\n"); printf("\t\t\t\t\t\t\t\t |\t 12、删除左子树 |\n"); printf("\t\t\t\t\t\t\t\t |\t 13、删除右子树 |\n"); printf("\t\t\t\t\t\t\t\t |\t 14、查找指定节点双亲 |\n"); printf("\t\t\t\t\t\t\t\t |\t 15、查找指定节点孩子 |\n"); printf("\t\t\t\t\t\t\t\t |\t 16、查找指定节点子孙 |\n"); printf("\t\t\t\t\t\t\t\t |\t 17、查找指定节点祖先 |\n"); printf("\t\t\t\t\t\t\t\t |\t 18、退出程序 |\n"); printf("\t\t\t\t\t\t\t\t\t*************************************\n"); printf("请输入你所需要完成的指令:\n"); do{ scanf("%d%*c",&n); if(n<1||n>18) printf("对不起,你输入的指令编号是无效的,请重新输入!!!\n"); }while(n<1||n>18); switch(n) { case 1: Pre_order_Creat_Btree(&root); printf("创建成功!\n"); system("pause"); break; case 2: printf("请输入要插入的字母:\n"); scanf("%c%*c",&ch); Insert_LeftNode(root,ch); printf("插入成功\n"); system("pause"); break; case 3: printf("请输入要插入的字母:\n"); scanf("%c%*c",&ch); Insert_RightNode(root,ch); printf("插入成功\n"); system("pause"); break; case 4: printf("请输入要查找的节点元素:\n"); scanf("%c%*c",&ch); head=root; Insearch_BTree(root,ch,head); if(head==NULL) printf("查找元素顶点不存在,查找失败!!!\n"); else printf("%c\n",head->data); system("pause"); break; case 5: BTree_leave_num(root,count); printf("二叉树叶子节点数目为:%d\n",count); system("pause"); break; case 6: printf("二叉树的深度为:%d\n", BTree_Depth_First(root)); BTree_Depth_Second(root,1,depth); printf("二叉树的深度为:%d\n",depth); system("pause"); break; case 7: printf("先序递归遍历后得到如下序列:\n"); Pre_order_Rec(root); printf("\n"); printf("中序遍历后得到如下序列:\n"); In_order_Rec(root); printf("\n"); printf("后序遍历后得到如下序列:\n"); Post_order_Rec(root); printf("\n"); system("pause"); break; case 8: printf("第一种先序遍历非递归结果如下:\n"); PreOrder_NonRec_First(root); printf("\n"); printf("第二种先序遍历非递归结果如下:\n"); PreOrder_NonRec_Second(root); printf("\n"); printf("第三种先序遍历非递归结果如下:\n"); PreOrder_NonRec_Third(root); printf("\n"); printf("第四种先序遍历非递归结果如下:\n"); PreOrder_NonRec_Fouth(root); printf("\n"); printf("第一种中序遍历非递归结果如下:\n"); InOrder_NonRec_First(root); printf("\n"); printf("第二种中序遍历非递归结果如下:\n"); InOrder_NonRec_Second(root); printf("\n"); printf("第三种中序遍历非递归结果如下:\n"); InOrder_NonRec_Third(root); printf("\n"); printf("第一种后序遍历非递归结果如下:\n"); PostOrder_NonRec_Second(root); printf("\n"); printf("第二种后序遍历非递归结果如下:\n"); PostOrder_NonRec_Third(root); printf("\n"); system("pause"); break; case 9: printf("第一种层次遍历后得到如下序列:\n"); LevelOrder_First(root); printf("\n"); printf("第二种层次遍历后得到如下序列:\n"); LevelOrder_Second(root); printf("\n"); printf("第三种层次遍历后得到如下序列:\n"); LevelOrder_Third(root); printf("\n"); system("pause"); break; case 10: NodeCount_Rec(root); printf("0度节点数目为:%d\n",count_leaf); printf("1度节点数目为:%d\n",count_onedegree); printf("2度节点数目为:%d\n",count_twodegree); count_leaf=count_onedegree=count_twodegree=0; system("pause"); break; case 11: Exchange_BTree(root); printf("左右子树交换成功!\n"); system("pause"); break; case 12: Delete_LeftTree(root); printf("删除左子树成功!\n"); system("pause"); break; case 13: Delete_RightTree(root); printf("删除右子树成功!\n"); system("pause"); break; case 14: head=arrow=root; printf("请输入你想要谁的父节点:\n"); scanf("%c%*c",&ch); head=root; Insearch_BTree(root,ch,head); Find_Parent_Bnode(root,head,&arrow); if(arrow==NULL) printf("查找节点不存在或者为根节点!!!\n"); else printf("节点%c的父节点是%c\n",head->data,arrow->data); system("pause"); break; case 15: head=root; printf("请输入你想要谁的孩子节点:\n"); scanf("%c%*c",&ch); head=root; Insearch_BTree(root,ch,head); Find_Child_Bnode(head,&p_lchild,&p_rchild); if(p_lchild==NULL&&p_rchild==NULL) printf("查找节点不存在或者为叶子节点!!!\n"); else if(p_lchild!=NULL&&p_rchild==NULL) printf("节点%c的左孩子是%c\n",head->data,p_lchild->data); else if(p_lchild==NULL&&p_rchild!=NULL) printf("节点%c的右孩子是%c\n",head->data,p_rchild->data); else printf("节点%c的左右孩子分别为%c和%c\n",head->data,p_lchild->data,p_rchild->data); system("pause"); break; case 16: head=root; printf("请输入你想要谁的子孙节点:\n"); scanf("%c%*c",&ch); head=root; Insearch_BTree(root,ch,head); FindDescendants_Blist(head); system("pause"); break; case 17: head=root; printf("请输入你想要谁的祖宗节点:\n"); scanf("%c%*c",&ch); head=root; Insearch_BTree(root,ch,head); FindAncersors_Blist(root,head); system("pause"); break; case 18: return ; default: Basic_operation(root); } Basic_operation(root); }
原文地址:http://blog.csdn.net/huangqiang1363/article/details/42318581