C语言树的非递归遍历和层次遍历

调试环境:win10+vs2015

树是一种非常重要的数据结构,遍历树就变得尤为重要。
这里主要讲利用栈实现非递归遍历二叉树和利用队列实现层次遍历二叉树。

非递归遍历
首先需要编写一个树的结构体和相关函数

//声明一个树的结构体
typedef struct Tree {
    char data;           //存放的数据
    struct Tree* left;   //指向左孩子
    struct Tree* right;  //指向右孩子
}Tree,*pTree;
//初始化化二叉链表
pTree Init() {
    pTree ptree = (pTree)malloc(sizeof(Tree));  //申请节点
    ptree->data = 0;                            //赋初值
    ptree->left = NULL;
    ptree->right = NULL;
    return ptree;                               //赋值
}
//先序遍历创建二叉链表
void Creat(pTree* ptree) {                      //传入一个树节点的指针
    char c;
    c = getchar();                              //获取控制台的一个字符
    if (c == '.')*ptree = NULL;                 //如果为“.”,就把该子树赋空
    else {
        *ptree = (pTree)malloc(sizeof(Tree));   //否则,申请节点
        (*ptree)->data = c;                     //赋值
        Creat(&((*ptree)->left));               //递归调用,创建左子树
        Creat(&((*ptree)->right));              //递归调用,创建右子树
    }
}

其次声明一个栈

//定义一个栈节点的结构体
typedef struct Stack {
    pTree ptree;          //存放子树
    struct Stack * next;  //指向下一个栈节点地址
}Stack,*pStack;

//初始化栈
pStack InitStack() {
    pStack ps = (pStack)malloc(sizeof(Stack));  //申请一个节点
    ps->next = NULL;                            //赋值
    ps->ptree = NULL;
    return ps;                                  //返回
}
//压栈
pStack PushStack(pStack* ps, pTree ptree) {      //因为要改变栈头结点的指向所以传入指针
    pStack temp = (pStack)malloc(sizeof(Stack)); //申请节点
    temp->next = (*ps)->next;                    //将申请的节点压入栈
    (*ps)->next = temp;
    temp->ptree = ptree;
    return *ps;                                  //返回
}
//弹栈
pStack PopStack(pStack* ps) {
    if (IsEmptyStack(*ps))return *ps;    //判断栈是否为空
    pStack temp = (*ps)->next;           //将栈头结点取出来
    (*ps)->next = temp->next;      
    free(temp);                          //释放
    temp = NULL;                         //置空
    return *ps;                          //返回
}
//判空
int IsEmptyStack(pStack ps) {
    if (ps->next == NULL)return 1;      //判断是否为空,是返回1
    else return 0;
}
//中序非递归遍历
void MidNotPrint(pTree ptree) {
    if (ptree == NULL)return;                    //如果是空树,直接返回
    pStack ps = InitStack();                     //初始化栈
    pTree temp = ptree;                          //做一个树的临时变量
    while (temp != NULL || !IsEmptyStack(ps)) {  //循环
        if (temp != NULL) {                      //当前树不为空
            PushStack(&ps, temp);                //压栈
            temp = temp->left;                   // 当前树变成其左子树
        }
        else {
            temp = ps->next->ptree;              //读取栈的第一个节点
            printf("%c ", temp->data);           //打印输出
            temp = temp->right;                  //转到右子树
            ps = PopStack(&ps);                  //当前节点弹栈
        }
    }
}

测试一下

int main() {
    pTree ptree = Init();    //初始化树
    Creat(&ptree);           //控制台输入字符串创建树
    MidNotPrint(ptree);      //中序非递归打印
    return 0;
}

控制台输入:abc..de.g..f…
输出结果:c b e g d f a

利用队列实现层次遍历
树的结构体定义和上面的相同,只不过多了函数

//队列实现层次遍历
void CengPrint(pTree ptree) {
    if (ptree == NULL)return;                            //判空
    pQueue pq = InitQueue();                             //初始化队列
    pq = PushQueue(&pq, ptree);                          //入队
    while (!IsEmptyQueue(pq)) { 
        pTree temp = pq->next->ptree;                    //读取节点信息
        printf("%c ", temp->data);                       //打印输出
        if (temp->left)PushQueue(&pq, temp->left);       //左子树不为空,左子树入队
        if (temp->right)PushQueue(&pq, temp->right);     //右子树不为空,右子树入队
        pq = PopQueue(&pq);                              //当前节点出队
    }
}

队列的结构体定义

//初始化队列
pQueue InitQueue() {
    pQueue pq = (pQueue)malloc(sizeof(Queue));  //申请节点
    pq->next = NULL;                            //赋初值
    pq->ptree = NULL;
    return pq;
}
//入队
pQueue PushQueue(pQueue* pq, pTree ptree) {
    pQueue temp = (*pq)->next;                         //当前节点的拷贝
    if (temp != NULL) {                                //判断队列是否不空
        while (temp->next != NULL)temp = temp->next;   //访问队列最后一个节点
        pQueue tmp = (pQueue)malloc(sizeof(Queue));    //申请空间
        tmp->ptree = ptree;                            //赋值
        tmp->next = NULL;
        temp->next = tmp;                              //改变指针指向
    }
    else {
        temp = (pQueue)malloc(sizeof(Queue));          //申请节点 
        temp->next = NULL;                             //赋值
        temp->ptree = ptree;
        (*pq)->next = temp;                            //改变指针指向
    }
    return *pq;
}
//出队
pQueue PopQueue(pQueue* pq) {
    if (IsEmptyQueue(*pq))return *pq;      //判空
    pQueue temp = (*pq)->next;             //改变指针指向
    (*pq)->next = temp->next;
    free(temp);                            //释放
    temp = NULL;                           //置空
    return *pq;
}
//判空
int IsEmptyQueue(pQueue pq) {
    if (pq->next == NULL)return 1;
    else return 0;
}

测试函数

int main() {
    pTree ptree = Init();
    Creat(&ptree);
    CengPrint(ptree);
    return 0;
}

控制台输入:abc..de.g..f…
运行后结果:a b c d e f g

总结:
利用栈和队列实现对树的遍历是数据结构里面最基础的算法,只有掌握好了他们才能够掌握更高大上的数据结构算法。

你可能感兴趣的:(树,C语言,非递归遍历,层次遍历)