目录
一、线性表中顺序表的实现:
二、线性表的链式存储(链表-带头节点)
三、习题练习:
四、栈(stack)
五、循环队列
1.数组形式:
2.链表形式:
3.习题练习
六、二叉树
1.层次建树
2.前中后序遍历 (就看中在哪遍历)
3.层序遍历--
4.先序遍历求WPL带权路径之和
七、OJ练习题
一、线性表中顺序表的实现:
注意:--顺序表其实就是数组 只是结构体中多存了一个数组的长度
理解原理:画框框 看怎么移动的
注意方法中引用
注意循环中起始位置--画图理解
--这里查看我实现的是按位置查找也可也写为按值查找 返回第一个位置/其他
--注意返回的是位置还是索引
#include <stdio.h>//顺序表的实现
#define MAXSIZE 50 //这里不加引号
typedef int ElemType; //使得顺序表存储其他类型元素时候可以迅速修改类型typedef struct {ElemType data[MAXSIZE];int len;
} SequenceTable;//遍历
void print_list(SequenceTable &list){for (int i = 0; i < list.len; ++i) {printf("The changed value is:%d\n",list.data[i]);}
}//顺序表中插入元素---这里list要(c++语法)引用
bool addData(SequenceTable &list,int position,ElemType data){//判断插入的位置是否合法---首尾判断 不能插入到 len+1以外的地方 不能插入到比1小的位置上if(position>list.len+1||position<1){printf("The location inserted into the table is illegal");return false;}//判断表中是否还有空间if(list.len>=MAXSIZE){printf("Insert failure space is full");return false;}//把要插入的空间腾出来 后面的元素往后移动一位for (int i = list.len-1; i >=position-1 ; i--) {list.data[i+1]=list.data[i];}//插入元素list.data[position-1]=data;//顺序表存储的元素长度+1list.len++;//遍历输出print_list(list);return true;
}//删除元素
bool delData(SequenceTable &list,int position){//判断删除的位置是否合法if(position>list.len||position<=0){//删除的位置不合法printf("The deleted location is invalid!");return false;}//删除该位置的元素--依次往前覆盖掉要删除的那个位置的元素for (int i = position; i < list.len; ++i) {list.data[i-1]=list.data[i];}//删除成功--改变线性表长度list.len--;//遍历print_list(list);return true;
}//修改元素
bool updateData(SequenceTable &list,int position,ElemType value){//判断修改的位置是否合法if(position>list.len||position<=0){//删除的位置不合法printf("The deleted location is invalid!");return false;}//修改元素list.data[position-1]=value;//遍历print_list(list);return true;
}int main() {SequenceTable list;list.data[0]=0;list.data[1]=1;list.data[2]=2;list.data[3]=3;list.len=4;for (int i = 0; i < list.len; ++i) {printf("Change the previous value to:%d\n",list.data[i]);}//插入
// addData(list,2,9);//删除
// delData(list,1);//修改updateData(list,1,8);return 0;
}
二、线性表的链式存储(链表-带头节点)
注意:
头插法构建链表:不要忘记引用--画图看指针域的改变--注意改变顺序
尾插法构建链表:要记录尾部节点--画图看指针域变化
按位置查找的时候返回节点地址:--(可以返回头节点地址--便于删除操作)
或者自己写一个单独获取前一个节点的方法
便于后续对链表的插入操作时查找要插入元素的前一个节点位置
节点的删除-----画图看指针域变化--注意要判断拿到的前一个节点是否为NULL
拿前一个节点的时候这个获取的方法是可以获取到头节点的
注意删除某个节点的时候不要忘记free() 释放该节点地址空间
typedef int ElementType;//存储的数据域类型
//linkList是指针别名 LNode* 就等价于 linkList
typedef struct LNode{
ElementType data;//数据域
struct LNode *next;//指针域
}LNode, *linkList;
#include <stdio.h>
#include <stdlib.h>//链表实现
typedef int ElementType;//存储的数据域类型//linkList是指针别名 LNode* 就等价于 linkList
typedef struct LNode{ElementType data;//数据域struct LNode *next;//指针域
}LNode, *linkList;//头插法构建链表--注意引用因为要改变
bool buildLinkListByHead(linkList &list){//申请(结构体节点)空间创建头节点list=(LNode*) malloc(sizeof(LNode));//初始化头节点的指针域list->next=NULL;//循环接收输入的数据 来构建链表ElementType x;//不要忘记引用scanf("%d",&x);while (x!=9999){//为新节点--申请节点空间LNode *new_node=(LNode*) malloc(sizeof (LNode));//存储数据new_node->data=x;//改变新节点的指针域--指向原来头节点的指针域所指向的节点地址new_node->next=list->next;//改变头节点的指针域--指向该元素list->next=new_node;//继续接收下一个数--不要忘记引用scanf("%d",&x);}return true;
}//尾插法构造链表
bool buildLinkListByTail(linkList &list){//申请头节点空间list=(linkList) malloc(sizeof (LNode));//初始化头节点指针域list->next=NULL;//接收数据xElementType x;scanf("%d",&x);//记录最后一个节点--初始化LNode *tailNode=list;while (x!=9999){//为新节点申请空间LNode *new_node=(LNode*) malloc(sizeof(LNode));//存储数据new_node->data=x;//改变新节点的指针域new_node->next=tailNode->next;//改变头节点的指针域tailNode->next=new_node;//插入完成 得到尾部节点tailNode=new_node;//继续接收数据scanf("%d",&x);}return true;
}//统计链表的长度
int getLength(linkList list){int length=0;list=list->next;while (list){length++;list=list->next;}return length;
}//按位置查找--本应该返回的是这个位置的节点地址
ElementType getValueByPosition(linkList list,int position){int value;int length= getLength(list);//判断位置是否合法if (position>length||position<=0){printf("The location entered is invalid!");return -1;}//遍历查找for (int i = 0; i < position; ++i) {//依次后移到该位置list=list->next;}if (list->data== NULL){return -1;}value=list->data;return value;
}//按位置查找--返回的是这个位置的节点地址
linkList getLNodeByPosition(linkList list,int position){int length= getLength(list);//判断位置是否合法if (position>length||position<=0){printf("The location entered is invalid!");return NULL;}//遍历查找for (int i = 0; i < position; ++i) {//依次后移到该位置list=list->next;}return list;
}//按值查找
int getPositionByValue(linkList list,int value){//得到第一个元素list=list->next;//记录位置int position=0;while (list&&list->data==value){//记录位置position++;//依次往后移动list=list->next;}return position;
}//找到要插入节点的前一个节点
linkList getBeforeNode(linkList list,int position){LNode *before_node=list;//当前位置int current=0;for (int i = 0; i < position-1; ++i) {before_node=before_node->next;}return before_node;
}//往第i个位置插入元素--要改变链表中 某些节点的指针域了 要用 引用
bool listFrontInsert(linkList &list,int position,ElementType e){//得到当前链表的长度int length= getLength(list);//判断插入的位置是否合法if (position<=0||position>length+1){printf("The insertion position is illegal!\n");return false;}//为要插入的节点申请节点空间LNode *new_node=(LNode*) malloc(sizeof(LNode));new_node->data=e;//得到要插入节点的前一个节点LNode *before_node=getBeforeNode(list,position);//改变插入节点的指针域new_node->next=before_node->next;//改变前一个节点的指针域before_node->next=new_node;return true;
}//遍历链表--这里不需要引用因为不对链表做改变仅遍历查看
void ergodicList(linkList list){//得到头节点所指向的元素list=list->next;//循环遍历while (list!=NULL){printf("%3d",list->data);//往后移动list=list->next;}//遍历完成--换行printf("\n");
}//链表的删除--要改变指针域 用引用
bool delLNode(linkList &list,int position){//得到链表的长度int length= getLength(list);//判断要删除的位置是否合法if (position>length||position<=0){printf("The location to be deleted is invalid");return false;}//得到要删除节点的前一个位置的节点LNode *before_node= getBeforeNode(list,position);//要做非空判断if (before_node==NULL){return false;}//得到要删除的节点LNode *delNode= getLNodeByPosition(list,position);//删除该节点before_node->next=delNode->next;delNode->next=NULL;//释放空间free(delNode);return true;
}int main() {linkList list;//头插法创建链表
// buildLinkListByHead(list);//尾插法创建链表buildLinkListByTail(list);//遍历查看ergodicList(list);//按位置查找
// int value=getValueByPosition(list,5);
// if (value!=-1){
// //查找成功
// printf("%d\n",value);
// }
// int position= getPositionByValue(list,9);
// if (position!=0){
// //查找成功
// printf("%d\n",position);
// }// //插入元素
// listFrontInsert(list,2,90);//按位置查找节点
// LNode *node=getLNodeByPosition(list,2);
// printf("%d\n",node->data);//删除节点delLNode(list,1);//遍历查看ergodicList(list);return 0;
}
三、习题练习:
1.一次循环--得中间节点--俩个指针 一个走2 一个走1
2.原地逆置-- -- 三个指针
3.轮流合并-- -- 三个指针
不清楚该不该引用 就再增删改的时候加引用即可
注意逆置侯L2的第一个节点要重置 且 第一个节点的尾指针要指向NULL
#include <stdio.h>
#include <stdlib.h>typedef struct node{int data;//数据域struct node *next;//指针域
}node;//尾插法构造链表
bool buildLinkListByTail(node* &list){//申请头节点空间list=(node*) malloc(sizeof (node));//初始化头节点指针域list->next=NULL;//接收数据xint x;scanf("%d",&x);//记录最后一个节点--初始化node *tailNode=list;while (x!=9999){//为新节点申请空间node *new_node=(node*) malloc(sizeof(node));//存储数据new_node->data=x;//改变新节点的指针域new_node->next=tailNode->next;//改变头节点的指针域tailNode->next=new_node;//插入完成 得到尾部节点tailNode=new_node;//继续接收数据scanf("%d",&x);}return true;
}//遍历链表--这里不需要引用因为不对链表做改变仅遍历查看
void ergodicList(node* list){//得到头节点所指向的元素list=list->next;//循环遍历while (list!=NULL){printf("%3d",list->data);//往后移动list=list->next;}//遍历完成--换行printf("\n");
}//查询链表的中间位置--并初始化后半部分链表L2--双指针遍历法--注意引用
void findMiddle(node* &L,node* &L2){//L非空判断if (L==NULL){return;}//为L2创建头节点L2=(node*) malloc(sizeof(node));//初始化头节点L2->next=NULL;//双指针遍历法查找中间节点node *before,*behind;//初始化 这俩个指针--都指向链表L的第一个节点before=behind=L->next;//循环移动 before每次移动一格 behind每次移动俩格while (behind!=NULL){//后面节点移动一格---不要一次移动俩格--可能移动一次就为空了behind=behind->next;//移动一次后--注意这里要非空判断if (behind==NULL){//说明已经找到了中间位置--这里退出循环break;}//不为空那么可以再移动一次behind=behind->next;//移动俩次后--要非空判断--因为只要behind为空那么 before是不可以移动的if (behind==NULL){//说明已经找到了中间位置--这里退出循环break;}//移动beforebefore=before->next;}//移动完成后 before所在的位置即为L2的头节点所在位置//before所在的位置的后一个节点即为L2的第一个节点所在位置L2->next=before->next;//断开L L2连接before->next=NULL;
}//原地翻转后半部分链表L2
void reverse(node* &L2){//非空判断if (L2==NULL){return;}//准备三个指针node *left,*middle,*right;//左边指向第一个节点left=L2->next;//判断第一个节点是否为空if (left==NULL){return;}//中间指向第二个节点middle=left->next;//判断第二个节点是否为空if (middle==NULL){return;}//右边指向第三个节点right=middle->next;//在循环中进行判断while (right!=NULL){//翻转//将中间节点的尾指针指向左边节点middle->next=left;//三个指针同时移动left=middle;//左边节点变中间节点middle=right;//中间节点变右边节点right=right->next;//右边节点移动一位}//不要忘记右边节点为空的时候--已经退出了循环--左中节点还未完成翻转middle->next=left;//因为要翻转--不要忘记L2的最后一个节点指向NULL--即刚开始的第一个节点L2->next->next=NULL;//翻转完成--重置L2的-第一个节点L2->next=middle;
}//交叉合并俩个链表--三指针法
void merge(node* L,node* L2){if (L==NULL||L2==NULL){return;}node *pcur;//始终指向合成的那个链表的尾部node *p;//指向L的第二个节点node *q;//指向L2的第一个节点pcur=L->next;p=pcur->next;q=L2->next;while (p!=NULL){//合并第一个q节点pcur->next=q;pcur=pcur->next;//后移一位pcurq=q->next;//后移一位q//合并第二个p节点pcur->next=p;pcur=pcur->next;p=p->next;}//看最后那个剩在哪个上 插入即可if (p!=NULL){pcur->next=p;pcur=pcur->next;}if (q!=NULL){pcur->next=q;pcur=pcur->next;}
}int main() {//初始链表Lnode* L;//尾插法创建链表LbuildLinkListByTail(L);//存储我们翻转后的链表L2node* L2=NULL;//初始L--遍历查看ergodicList(L);printf("------------\n");//查询链表L的中间位置并初始化后半部分链表为L2findMiddle(L,L2);//打印L与L2ergodicList(L);ergodicList(L2);printf("------------\n");//翻转reverse(L2);ergodicList(L2);printf("-------------\n");//合并merge(L,L2);ergodicList(L);return 0;
}
四、栈(stack)
栈:数组实现
初始化栈:栈顶=-1 即为空栈
出栈:并不会改变数组 --只是让栈顶-1
入栈:会改变数组元素
#include <stdio.h>#define MAXSIZE 50
typedef int ElementType;typedef struct {//栈中的元素--数组存储ElementType data[MAXSIZE];//始终指向栈顶的一个变量--因为是数组因此从0开始//空栈为-1int top;
}Stack;//初始化栈
bool InitStack(Stack &stack){stack.top=-1;return true;
}//判断栈满
bool isStackFull(Stack stack){if (stack.top>=MAXSIZE-1){return true;}return false;
}//判断栈空
bool isStackEmpty(Stack stack){if (stack.top==-1){return true;}return false;
}//进栈
bool push(Stack &stack,ElementType x){//判断栈是否已满bool isFull=isStackFull(stack);if (isFull){return false;}//进栈stack.data[++stack.top]=x;
}//出栈-返回出栈元素
bool pop(Stack &stack,ElementType &x){//判断是否为空if (isStackEmpty(stack)){return false;}//出栈x=stack.data[stack.top--];
}int main() {Stack stack;InitStack(stack);push(stack,1);push(stack,2);ElementType x;pop(stack,x);printf("%d--%d",x,stack.top);return 0;
}
五、循环队列
1.数组形式:
1.注意是循环队列
queue.rear=(queue.rear+1)%MAXSIZE;queue.front=(queue.front+1)%MAXSIZE;判断队空:--画图
queue.front==queue.rear判断队满:--画图
(queue.rear+1)%MAXSIZE==queue.front
#include <stdio.h>#define MAXSIZE 3typedef int ElementType;
typedef struct {//数组存储--只能存储MAXSIZE-1个元素(便于判断队满)ElementType data[MAXSIZE];//队列尾 队列头int rear,front;
}Queue;//判断队满
bool isQueueFull(Queue queue){if ((queue.rear+1)%MAXSIZE==queue.front){return true;}return false;
}//判断队空
bool isQueueEmpty(Queue queue){if (queue.front==queue.rear){return true;}return false;
}//初始化队列
bool InitQueue(Queue &queue){//头和尾都指向零号元素queue.front=queue.rear=0;return true;
}//入队
bool push(Queue &queue,ElementType x){//判断队满if (isQueueFull(queue)){return false;}//入队queue.data[queue.rear]=x;//注意这里要循环queue.rear=(queue.rear+1)%MAXSIZE;return true;
}//出队
bool pop(Queue &queue,ElementType &x){if (isQueueEmpty(queue)){return false;}//出队x=queue.data[queue.front];//注意这里要循环queue.front=(queue.front+1)%MAXSIZE;return true;
}int main() {Queue queue;InitQueue(queue);push(queue,1);push(queue,2);push(queue,3);ElementType x;pop(queue,x);printf("%d--%d",queue.rear,queue.front);return 0;
}
2.链表形式:
尾插法:入队
出队: 头节点连接下一个
具体可以看动画
Data Structure Visualization (usfca.edu)
注意:
初始化链表队列时候 头节点的尾指针
出队的时候要判断删除完后是否为队空 如果队空 --重置front与rear--free()-注意顺序
重置front与rear: queue.rear=queue.front----注意重置的是rear
出队:判断栈空--出队-得到第一个节点-改变front--判断队空--free
#include <stdio.h>
#include <stdlib.h>//循环队列的链式表示
typedef int ElementType;//链表
typedef struct LinkNode{ElementType data;struct LinkNode *next;
}LinkNode;//链表队列
typedef struct LinkQueue{//链表队列头 链表队列尾LinkNode *front,*rear;
}LinkQueue;//先进先出//初始化链表队列
void InitLinkQueue(LinkQueue &linkQueue){//申请节点空间//都指向头节点linkQueue.front=linkQueue.rear=(LinkNode *) malloc(sizeof(LinkNode));//初始化头节点linkQueue.front->next=NULL;
}//判断队空
bool isEmpty(LinkQueue queue){if (queue.front==queue.rear){return true;}return false;
}//因为是链表可以自己申请空间 所以不存在队满的情况//入队--类似尾插法
void push(LinkQueue &queue,ElementType x){//为新节点申请空间LinkNode *newNode=(LinkNode*) malloc(sizeof(LinkNode));newNode->data=x;//连接导队列上newNode->next=queue.rear->next;queue.rear->next=newNode;//rear始终指向队列尾queue.rear=newNode;}//出队--front往后移动
bool pop(LinkQueue &queue,ElementType &x){//判断队中是否为空if (isEmpty(queue)){return false;}//得到出队的该节点LinkNode *node=queue.front->next;//出队x=node->data;//不是最后一个元素-后面还有元素则--断链queue.front->next=node->next;//判断删除的是否是队列的最后一个节点if (node==queue.rear){//说明删除完后队列--队列为空了--重置rear与front//注意重置是给rear重新指向头节点 因为后面没元素了 要重置就是重置的rearqueue.rear=queue.front;}free(node);return true;
}int main() {LinkQueue linkQueue;InitLinkQueue(linkQueue);push(linkQueue,1);ElementType x;pop(linkQueue,x);return 0;
}
3.习题练习
六、二叉树
1.层次建树
注意:
先画图在编写代码
因为是逐层判断那么插入一个节点处理完成后要跳过后续处理进行下一个节点的处理
不要忘记重置树根节点与队列尾节点
#include <stdio.h>
#include <stdlib.h>//树中元素的存储类型
typedef char BiElementType;//树的结构
typedef struct BiTNode{//存储数据BiElementType data;//左孩子struct BiTNode *lchild;//右孩子struct BiTNode *rchild;
}BiTNode,*BiTree;//辅助队列
typedef struct tag{//存储的是树中节点的地址BiTree p;struct tag *pnext;
}tag_t,*ptag_t;
#include "BiTree.h"int main() {//用来指向新申请的树节点BiTree tnode;//始终指向要插入节点的父亲节点BiTree tree=NULL;//始终指向树根BiTree troot=NULL;//接收数据BiElementType c;//队列头 队列尾 申请新的队列节点空间 pnew pcur 指向(正在插入左右孩子的)二叉树的根节点ptag_t phead=NULL,ptail=NULL,pnew=NULL,pcur=NULL;//循环接收键盘输入abcdefjhwhile (scanf("%c",&c)){//退出循环if (c=='\n'){break;}//创建新的树节点--创建树节点空间--calloc() 俩个参数之积 为申请的空间大小--于malloc相比它会自动初始化--初始化为0 0即为NULLtnode=(BiTNode*) calloc(1, sizeof(BiTNode));//初始化树节点tnode->data=c;//申请队列节点空间pnew=(tag_t*) calloc(1, sizeof(tag_t));//初始化--数据为 树中节点的地址pnew->p=tnode;//判断树是否为空if (tree==NULL){//第一次插入树--将当前节点作为树根节点troot=tnode;//将当前节点作为接下来要插入节点的父亲节点节点tree=tnode;//入队//队列头节点赋值phead=pnew;//队列中的树根节点--指要进入树的父亲节点pcur=pnew;//队列尾节点重置ptail=pnew;//那么这个节点就处理完成了continue;}//如果树不为空判断是否为左孩子if (tree->lchild==NULL){//左孩子连接树tree->lchild=tnode;//左孩子入队pnew->pnext=ptail->pnext;ptail->pnext=pnew;//队列尾节点重置ptail=pnew;//那么这个节点就处理完成了continue;}//如果树不为空判断是否为右孩子if (tree->rchild==NULL){//右孩子连接到树上tree->rchild=tnode;//右孩子入队pnew->pnext=ptail->pnext;ptail->pnext=pnew;//注意因为是右孩子因此此时的树根节点以及满了 要改变树根了//移动队列中的树根节点pcur=pcur->pnext;//将辅助队列树根节点赋值给树根节点tree=pcur->p;//队列尾节点重置ptail=pnew;//那么这个节点就处理完成了continue;}}return 0;
}
2.前中后序遍历 (就看中在哪遍历)
就看中间节点在哪遍历:
(先)前序--深度优先遍历:中左右
中序:左中右
后序:左右中
递归实现:注意循环退出条件--改变输出顺序即可
//前序遍历
void preOrder(BiTree tree){if (tree==NULL){return;}//中左右printf("%c",tree->data);//打下面的preOrder(tree->lchild);preOrder(tree->rchild);
}
//中序
void inOrder(BiTree tree){if (tree==NULL){return;}//左中右inOrder(tree->lchild);printf("%c",tree->data);inOrder(tree->rchild);
}//后序
void postOrder(BiTree p){if (p==NULL){return;}//左右中postOrder(p->lchild);postOrder(p->rchild);printf("%c",p->data);
}
3.层序遍历--
树根节点入队循环不为空的队列:
将根节点出队
分别将根节点的左孩子与后孩子分别入队
出队在一次放入出队节点的左右孩子
以此往复直到队列为空
//层序遍历
void LevelOrder(BiTree troot){if (troot==NULL){return;}//辅助队列LinkQueue queue;InitLinkQueue(queue);//树根节点放入队列push(queue,troot);//存储出队树节点BiTNode *deNode;while (!isEmpty(queue)){pop(queue,deNode);putchar(deNode->data);if(deNode->lchild){//左孩子入队push(queue,deNode->lchild);}if(deNode->rchild){//右孩子入队push(queue,deNode->rchild);}}
}
注意队列最后一个节点出队的front与rear的重置
4.先序遍历求WPL带权路径之和
第一种,使用静态局部遍历累加的形式:
1.遍历左孩子 deep+1
2.遍历右孩子 deep+1
第二种,使用递归直接返回:
1.这个递归表示该子树的带权路径之和=左子树+右子树的带权路径之和
2.返回条件为如果这个节点满足叶子节点就返回它的带权路径
//先序遍历计算带权路径之和
int wpl_preOrder(BiTree tree,int deep){//静态局部变量 它与全局变量作用类似 都只会初始化一次 但它仅在函数内有效static int wpl=0;if (tree!=NULL){if (tree->lchild==NULL&& tree->rchild==NULL){wpl+=tree->data*deep;}wpl_preOrder(tree->lchild,deep+1);wpl_preOrder(tree->rchild,deep+1);}return wpl;
}
//先序遍历计算带权路径之和
int wpl_PreOrder(BiTree tree,int deep){if (tree->lchild==NULL&&tree->rchild==NULL){return tree->data*deep;}return wpl_PreOrder(tree->lchild,deep+1)+wpl_PreOrder(tree->rchild,deep+1);
}
七、OJ练习题
注意增删改加引用
注意当第一个节点入队的时候
将这第一个节点作为接下来的父亲节点 qroot=queue.front->next 不要忘记next
#include <stdio.h>
#include <stdlib.h>/*** 读取字符串abcdefghij,然后层次建树建立一颗二叉树,然后前序遍历输出abdhiejcfg,注意不要打印前序遍历几个汉字*//*** 读取字符串abcdefghij,然后层次建树建立一颗二叉树,* 然后中序遍历输出 hdibjeafcg,后序遍历输出 hidjebfgca,层序遍历输出abcdefghij,注意不要输出汉字*/typedef char BiElementType;
typedef struct BiNode{BiElementType data;BiNode *lchild,*rchild;
}BiNode,*BiTree;typedef BiTree QElementType;//辅助链式循环队列
typedef struct LinkNode{QElementType data;struct LinkNode *next;
}LinkNode,*LinkList;typedef struct LinkQueue{LinkNode *front,*rear;
}LinkQueue;//判断队列是否为空
bool isEmptyQueue(LinkQueue queue){return queue.front==queue.rear;
}
//初始化队列
void InitQueue(LinkQueue &queue){queue.rear=queue.front=(LinkNode*) calloc(1,sizeof (LinkNode));
}//入队
void enQueue(LinkQueue &queue,QElementType data){//存储新节点LinkNode* qnew=(LinkNode*) calloc(1, sizeof(LinkNode));qnew->data=data;//入队qnew->next=queue.rear->next;queue.rear->next=qnew;queue.rear=qnew;
}
//出队
BiTree deQueue(LinkQueue &queue){if (isEmptyQueue(queue)){return NULL;}//获取当前出队节点LinkNode *qNode=queue.front->next;//出队queue.front->next=qNode->next;if (queue.rear==qNode){//说明删除的是最后一个节点--重置rear frontqueue.rear=queue.front;}BiNode *tree=qNode->data;//释放空间free(qNode);return tree;
}//层次建树
BiTree buildBiTree(BiTree &tree){//存储新的树节点BiNode *tnew=NULL;BiElementType data;//创建辅助队列并初始化LinkQueue queue;InitQueue(queue);//队列中--指向要插入的节点的父亲节点LinkNode *qroot=NULL;//树根节点BiTree troot=NULL;while (scanf("%c",&data)){if (data=='\n'){break;}tnew=(BiNode*) calloc(1,sizeof(BiNode));tnew->data=data;//判断是否是树根节点if (tree==NULL){tree=tnew;enQueue(queue,tnew);//此时队列中的第一个节点作为接下来要插入的父节点qroot=queue.front->next;troot=tnew;continue;}//判断是否是左孩子节点if (tree->lchild==NULL){tree->lchild=tnew;enQueue(queue,tnew);continue;}//判断是否是右孩子节点if (tree->rchild==NULL){tree->rchild=tnew;enQueue(queue,tnew);qroot=qroot->next;tree=qroot->data;continue;}}return troot;
}//前序
void preOrder(BiTree tree){if (tree==NULL){return;}printf("%c",tree->data);preOrder(tree->lchild);preOrder(tree->rchild);
}//中序
void inOrder(BiTree tree){if (tree==NULL){return;}inOrder(tree->lchild);printf("%c",tree->data);inOrder(tree->rchild);
}
//后序
void PostOrder(BiTree tree){if (tree==NULL){return;}PostOrder(tree->lchild);PostOrder(tree->rchild);printf("%c",tree->data);
}
//层序
void SequenceOrder(BiTree tree){if (tree==NULL){return;}LinkQueue queue;InitQueue(queue);enQueue(queue,tree);while (!isEmptyQueue(queue)){BiNode *tree=deQueue(queue);printf("%c",tree->data);if (tree->lchild){enQueue(queue,tree->lchild);}if (tree->rchild){enQueue(queue,tree->rchild);}}
}int main() {BiTree tree=NULL;BiTree troot=NULL;troot=buildBiTree(tree);inOrder(troot);printf("\n");PostOrder(troot);printf("\n");SequenceOrder(troot);printf("\n");return 0;
}