数据结构之非递归遍历和层次遍历(C语言版)

来源:互联网 发布:如何优化前端页面 编辑:程序博客网 时间:2024/05/21 10:48

调试环境: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

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

0 0