C语言(链表、栈、树)

简介: C语言(链表、栈、树)

一、链表


1、link.c文件内容


#include <stdlib.h>
#include "01link.h"
//链表的初始化函数
void link_init(link *p_link) {
    p_link->head.p_next = &p_link->tail;   //头节点向后指向尾节点
    p_link->tail.p_next = NULL;    //尾节点里的指针设置为空指针
    p_link->tail.p_prev = &p_link->head;  //尾节点向前指向头节点
    p_link->head.p_prev = NULL;    //头节点里向前的指针设置为空指针
    p_link->p_cur = NULL;    //链表没有处于遍历状态
}
//链表的清理函数
void link_deinit(link *p_link) {
    node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    p_link->p_cur = NULL;      //链表没有处于遍历状态
    //每次循环删除头节点后面的有效节点
    while (p_link->head.p_next != &p_link->tail) {   //头节点后面不是尾节点
        //把三个指针指向链表最前面的
        //三个节点
        p_first = &p_link->head;
        p_mid = p_first->p_next;
        p_last = p_mid->p_next;
        //把p_mid指针指向的节点从链式物理
        //结构里摘出来
        p_first->p_next = p_last;
        p_last->p_prev = p_first;
        //释放p_mid指针指向的节点
        free(p_mid);
        p_mid = NULL;
    }
}
//获得链表里数字个数的函数
int link_size(const link *p_link) {
    int cnt = 0;
    const node *p_tmp = NULL;
    //编写for循环统计链表里的有效节点个数
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        const node *p_first = p_tmp;
        const node *p_mid = p_first->p_next;   //从第一个有效节点一直指到尾节点
        const node *p_last = p_mid->p_next;
        if (p_mid != &p_link->tail) {    //p_mid指针不是指向尾节点就一定指向一个有效节点
            cnt++;
        }
    }
    return cnt;
}
//判断链表是否空的函数
int link_empty(const link *p_link) {
    return p_link->head.p_next == &p_link->tail;  //头节点后面就是尾节点就表示链表是空的
}
//在链表最后插入新数字的功能
int link_append(link *p_link, int val) {
    node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    node *p_node = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    p_node = (node *)malloc(sizeof(node));   //动态分配节点记录新加入的数字
    if (!p_node) {
        //动态分配失败
        return 0;
    }
    p_node->val = val;     //把新数字记录到动态分配节点里
    p_node->p_next = NULL;
    p_node->p_prev = NULL;
    //让p_mid指针指向尾节点(p_first和p_mid中间就是要插入的位置)
    p_first = p_link->tail.p_prev;   //p_first指向最后一个有效节点
    p_mid = p_first->p_next;
    p_last = p_mid->p_next;
    //把新节点插入到p_first和p_mid中间
    p_first->p_next = p_node;
    p_node->p_next = p_mid;
    p_mid->p_prev = p_node;
    p_node->p_prev = p_first;
    return 1;
}
/*int link_append(link *p_link, int val) {
    node *p_tmp = NULL;
    node *p_node = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    p_node = (node *)malloc(sizeof(node));   //动态分配节点用来记录要加入的数字
    if (!p_node) {
        //动态分配内存失败的情况
        return 0;
    }
    p_node->val = val;    //把要插入的数字记录到动态分配的节点里
    p_node->p_next = NULL;
    p_node->p_prev = NULL;
    //编写for循环依次处理链表里所有可插入的位置
    //直到找到最后的可插入位置
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        node *p_first = p_tmp;
        node *p_mid = p_first->p_next;
        node *p_last = p_mid->p_next;
        if (p_mid == &p_link->tail) {    //p_mid指针指向尾节点的时候p_first和p_mid中间就是最后的可插入位置
            //把新节点插入到p_first和p_mid中间
            p_first->p_next = p_node;
            p_node->p_next = p_mid;
            p_mid->p_prev = p_node;
            p_node->p_prev = p_first;
            break;
        }
    }
    return 1;
}*/
//在链表开头插入新数字的函数
int link_add_head(link *p_link, int val) {
    node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    node *p_node = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    p_node = (node *)malloc(sizeof(node));
    if (!p_node) {
        return 0;
    }
    p_node->val = val;
    p_node->p_next = NULL;
    p_node->p_prev = NULL;
    //让三个节点指针指向链表最前面的三个节点
    //p_first和p_mid中间的位置就是最前面
    //的可插入位置
    p_first = &p_link->head;
    p_mid = p_first->p_next;
    p_last = p_mid->p_next;
    //把新节点插入到p_first和p_mid中间
    p_first->p_next = p_node;
    p_node->p_next = p_mid;
    p_mid->p_prev = p_node;
    p_node->p_prev = p_first;
    return 1;
}
//按照从小到大的顺序在链表里插入数字的函数
int link_insert(link *p_link, int val) {
    node *p_tmp = NULL;
    node *p_node = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    p_node = (node *)malloc(sizeof(node));
    if (!p_node) {
        return 0;
    }
    p_node->val = val;
    p_node->p_next = NULL;
    p_node->p_prev = NULL;
    //编写for循环找到要插入的位置
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        node *p_first = p_tmp;
        node *p_mid = p_first->p_next;
        node *p_last = p_mid->p_next;
        if (p_mid == &p_link->tail /*新数字比原来的所有数字都大,新节点应该插入到尾节点的前面*/ || p_mid->val > val /*p_mid指针指向节点里的数字比新数字大,新节点应该插入到p_first和p_mid中间*/) {
            //把新节点插入到p_first和p_mid中间
            p_first->p_next = p_node;
            p_node->p_next = p_mid;
            p_mid->p_prev = p_node;
            p_node->p_prev = p_first;
            break;
        }
    }
    return 1;
}
//删除最后一个数字的函数
int link_remove_tail(link *p_link) {
    node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    if (p_link->head.p_next == &p_link->tail) {   //头节点的后面就是尾节点
        //链表是空的,不存在最后一个数字
        return 0;
    }
    //让三个节点指针指向链表最后的三个节点
    p_last = &p_link->tail;
    p_mid = p_last->p_prev;    //p_mid指针指向最后一个有效节点
    p_first = p_mid->p_prev;
    //把p_mid指针指向的节点从链式物理结构里
    //摘出来
    p_first->p_next = p_last;
    p_last->p_prev = p_first;
    free(p_mid);    //释放p_mid指针指向的节点
    p_mid = NULL;
    return 1;
}
/*int link_remove_tail(link *p_link) {
    node *p_tmp = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    //编写for循环找到最后一个数字所在
    //的节点
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        node *p_first = p_tmp;
        node *p_mid = p_first->p_next;
        node *p_last = p_mid->p_next;
        if (p_last == &p_link->tail) {    //p_last指针指向尾节点的时候p_mid指针应该指向最后一个有效节点
            //首先把p_mid指针指向的节点
            //从链式物理结构中摘出来
            p_first->p_next = p_last;
            p_last->p_prev = p_first;
            free(p_mid);     //释放p_mid指针指向的节点
            p_mid = NULL;
            return 1;
        }
    }
    return 0;
}*/
//从链表里删除最前面数字的函数
int link_remove_head(link *p_link) {
    node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    if (p_link->head.p_next == &p_link->tail) {
        //头节点后面就是尾节点表示链表是空的
        return 0;
    }
    //让三个节点指针指向链表最前面的三个节点
    p_first = &p_link->head;
    p_mid = p_first->p_next;   //p_mid指针指向第一个有效节点
    p_last = p_mid->p_next;
    //把p_mid指针指向的节点从链式物理结构里
    //摘出来
    p_first->p_next = p_last;
    p_last->p_prev = p_first;
    free(p_mid);   //释放p_mid指针指向的节点
    p_mid = NULL;
    return 1;
}
//删除链表中间某个数字的函数
int link_remove(link *p_link, int val/*要删除的数字*/) {
    node *p_tmp = NULL;
    p_link->p_cur = NULL;    //结束遍历过程(退出遍历状态)
    //编写for循环找到要删除的节点
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        node *p_first = p_tmp;
        node *p_mid = p_first->p_next;
        node *p_last = p_mid->p_next;
        if (p_mid != &p_link->tail/*p_mid指针不是指向尾节点*/ && p_mid->val == val/*p_mid指针指向节点里的数字就是要删除的数字*/) {
            //把p_mid指针指向的节点从链式物理结构里摘出来
            p_first->p_next = p_last;
            p_last->p_prev = p_first;
            free(p_mid);     //释放p_mid指针指向的节点
            p_mid = NULL;
            return 1;
        }
    }
    return 0;
}
//获得链表里最后一个数字的函数
int link_get_tail(const link *p_link, int *p_val) {
    const node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    if (p_link->head.p_next == &p_link->tail) {  //头节点后面就是尾节点
        //链表是空的,无法获得最后一个数字
        return 0;
    }
    //让三个节点指针指向链表最后的三个节点
    p_last = &p_link->tail;
    p_mid = p_last->p_prev;    //p_mid指针指向最后一个有效节点
    p_first = p_mid->p_prev;
    *p_val = p_mid->val;     //把p_mid指针指向节点里的数字传递给调用函数
    return 1;
}
#if   0
int link_get_tail(const link *p_link, int *p_val/*把得到的数字传递给调用函数*/) {
    const node *p_tmp = NULL;
    //编写for循环找到最后一个有效节点
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        const node *p_first = p_tmp;
        const node *p_mid = p_first->p_next;
        const node *p_last = p_mid->p_next;
        if (p_last == &p_link->tail/*p_last指针指向尾节点的时候p_mid指针应该指向最后一个有效节点*/) {
            *p_val = p_mid->val;    //把p_mid指针指向的存储区里的数字传递给调用函数
            return 1;
        }
    }
    return 0;
}
#endif
//获得最前面数字的函数
int link_get_head(const link *p_link, int *p_val) {
    const node *p_first = NULL, *p_mid = NULL, *p_last = NULL;
    if (p_link->head.p_next == &p_link->tail) {
        //头结点后面就是尾节点表示链表是空的
        return 0;
    }
    //让三个节点指针指向链表最前面的三个节点
    p_first = &p_link->head;
    p_mid = p_first->p_next;   //p_mid指针指向第一个有效节点
    p_last = p_mid->p_next;
    *p_val = p_mid->val;    //把p_mid指针指向的节点里的数字传递给调用函数
    return 1;
}
//根据编号获得数字的函数
int link_get(const link *p_link, int *p_val, int sn/*给定的编号*/) {
    int cnt = 0;
    const node *p_tmp = NULL;
    //编写for循环找到编号sn对应的节点
    for (p_tmp = &p_link->head;p_tmp != &p_link->tail;p_tmp = p_tmp->p_next) {
        const node *p_first = p_tmp;
        const node *p_mid = p_first->p_next;
        const node *p_last = p_mid->p_next;
        if (p_mid != &p_link->tail/*p_mid指针不是指向尾节点*/ && cnt == sn/*cnt是p_mid指针指向节点的编号,cnt等于sn表示p_mid指针指向的节点就是要找的节点*/) {
            *p_val = p_mid->val;    //把p_mid指针指向的节点里的数字传递给调用函数
            return 1;
        }
        cnt++;
    }
    return 0;
}
//让链表开始从前向后遍历的函数
void link_begin(link *p_link) {
    p_link->p_cur = &p_link->head;   //把头结点作为上一次操作的节点记录下来
}
//在从前向后遍历过程中获得下一个数字的函数
int link_next(link *p_link, int *p_val) {
    if (!p_link->p_cur) {
        //排除没有处于遍历状态的情况
        return 0;
    }
    p_link->p_cur = p_link->p_cur->p_next;   //找到这次要操作的节点并记录下来
    if (p_link->p_cur == &p_link->tail) {
        //这次要操作的节点如果是尾节点就表示已经处理完链表里的所有节点
        p_link->p_cur = NULL;   //结束遍历过程
        return 0;
    }
    else {
        *p_val = p_link->p_cur->val;    //把这次要操作节点里的数字传递给调用函数
        return 1;
    }
}
//开始从后向前遍历链表里的所有节点
void link_rbegin(link *p_link) {
    p_link->p_cur = &p_link->tail;   //把尾节点作为上次操作的节点记录下来,下次操作的一定是尾节点前面的节点
}
//在从后向前遍历过程中获得前一个数字的函数
int link_prev(link *p_link, int *p_val) {
    if (!p_link->p_cur) {
        //如果没有处于遍历状态就结束函数
        return 0;
    }
    p_link->p_cur = p_link->p_cur->p_prev;   //找到这次要操作的节点并记录下来
    if (p_link->p_cur == &p_link->head) {
        //如果这次要操作的节点是头结点
        //就表示这次遍历过程结束了
        p_link->p_cur = NULL;   //结束遍历过程
        return 0;
    }
    else {
        *p_val = p_link->p_cur->val;   //把当前操作节点里的数字传递给调用函数
        return 1;
    }
}


2、link.h文件内容


#ifndef           __01LINK_H__
#define           __01LINK_H__
typedef struct node {
    int val;
    struct node *p_prev;    //指向前一个节点
    struct node *p_next;    //指向后一个节点
} node;    //代表节点的结构体
typedef struct {
    node head;    //头节点
    node tail;    //尾节点
    node *p_cur;  //记录遍历过程中上一次操作的节点
} link;    //代表链表的结构体
//链表的初始化函数
void link_init(link *);
//链表的清理函数
void link_deinit(link *);
//获得链表里数字个数的函数
int link_size(const link *);
//判断链表是否空的函数
int link_empty(const link *);
//在链表最后插入新数字的功能
int link_append(link *, int );
//在链表开头插入新数字的函数
int link_add_head(link *, int );
//按照从小到大的顺序在链表里插入数字的函数
int link_insert(link *, int );
//删除最后一个数字的函数
int link_remove_tail(link *);
//从链表里删除最前面数字的函数
int link_remove_head(link *);
//删除链表中间某个数字的函数
int link_remove(link *, int /*要删除的数字*/);
//获得链表里最后一个数字的函数
int link_get_tail(const link *, int */*把得到的数字传递给调用函数*/);
//获得最前面数字的函数
int link_get_head(const link *, int *);
//根据编号获得数字的函数
int link_get(const link *, int *, int /*给定的编号*/);
//开始从前向后遍历链表的函数
void link_begin(link *);
//在从前向后遍历链表的过程中获得下一个数字的函数
int link_next(link *, int *);
//开始从后向前遍历链表的函数
void link_rbegin(link *);
//在从后向前遍历链表的过程中获得前一个数字的函数
int link_prev(link *, int *);
#endif           //__01LINK_H__


3、link主函数内容


#include <stdio.h>
#include "01link.h"
int main() {
    int val = 0, size = 0, num = 0;
    link lnk = {0};
    link_init(&lnk);
    link_add_head(&lnk, 50);
    link_add_head(&lnk, 30);
    link_append(&lnk, 80);
    link_append(&lnk, 100);
    //以上四个数字按照从小到大的顺序排列
    link_insert(&lnk, 60);
    link_insert(&lnk, 20);
    link_insert(&lnk, 40);
    link_insert(&lnk, 90);
    link_insert(&lnk, 70);
    link_insert(&lnk, 10);
    link_remove_head(&lnk);
    link_remove_tail(&lnk);
    link_remove(&lnk, 50);
    link_get_head(&lnk, &val);
    printf("最前面的数字是%d\n", val);
    link_get_tail(&lnk, &val);
    printf("最后面的数字是%d\n", val);
    size = link_size(&lnk);    //获得链表里的数字 个数并记录到size变量里
    for (num = 0;num <= size - 1;num++) {
        link_get(&lnk, &val, num);
        printf("%d ", val);
    }
    printf("\n");
    link_begin(&lnk);     //把链表设置成从前向后的遍历状态
    while (1) {
        if (!link_next(&lnk, &val)) {   //在从前向后遍历过程中获得下一个数字
            //如果不能获得下一个数字就可以
            //结束循环了
            break;
        }
        printf("%d ", val);
    }
    printf("\n");
    link_rbegin(&lnk);    //把链表设置成从后向前遍历的状态
    while (1) {
        if (!link_prev(&lnk, &val)) {    //在从后向前遍历过程中获得前一个数字
            //如果无法继续获得数字就结束循环
            break;
        }
        printf("%d ", val);
    }
    printf("\n");
    link_deinit(&lnk);
    return 0;
}
运行结果:
最前面的数字是20
最后面的数字是90
20 30 40 60 70 80 90
20 30 40 60 70 80 90
90 80 70 60 40 30 20


二、栈操作


1、stack.c文件内容


#include "01stack.h"
//栈的初始化函数
void stack_init(stack *p_stack/*指向调用函数提供的一个代表栈的结构体存储区*/) {
    p_stack->qty = 0;    //表示栈里没有数字
}
//栈的清理函数
void stack_deinit(stack *p_stack) {
    p_stack->qty = 0;    //数字个数设置为0就表示把所有数字都删除了
}
//获得数字个数的函数
int /*得到的数字个数*/stack_size(const stack *p_stack) {
    return p_stack->qty;
}
//判断栈是否空的函数
int /*返回值为真表示栈是空的,否则栈不是空的*/stack_empty(const stack *p_stack) {
    return !p_stack->qty;
}
//判断栈是不是满的函数
int /*返回值为真表示栈是满的,否则栈不是满的*/stack_full(const stack *p_stack) {
    return p_stack->qty >= SIZE;
}
//向栈里加入数字的函数
int /*返回值为真表示加入成功,否则加入失败*/stack_push(stack *p_stack, int val/*表示要加入的数字*/) {
    if (p_stack->qty >= SIZE) {
        //栈已经满了
        return 0;
    }
    p_stack->buf[p_stack->qty] = val;   //把新数字放在数组里以qty做下标的存储区里
    p_stack->qty++;    //把栈里的数字个数加一
    return 1;
}
//从栈里获得一个数字的函数(同时把数字从栈里删除)
int /*返回值为真表示获得数字成功,为假表示失败*/stack_pop(stack *p_stack, int *p_val/*把得到的数字记录到这个指针指向的整数类型存储区里*/) {
    if (!p_stack->qty) {
        //处理栈为空的情况
        return 0;
    }
    *p_val = p_stack->buf[p_stack->qty - 1];    //qty - 1做下标的存储区里放的就是最后一个数字,把这个数字赋值给整数指针形参指向的存储区
    p_stack->qty--;     //数字个数减一就相当于把最后一个数字删除
    return 1;
}
//从栈里获得最后一个数字的函数(不会从栈里删除数字)
int /*返回值为真表示成功获得数字,为假表示没有获得数字*/stack_top(const stack *p_stack, int *p_val) {
    if (!p_stack->qty) {
        //处理栈为空的情况
        return 0;
    }
    *p_val = p_stack->buf[p_stack->qty - 1];
    return 1;
}

2、stack.h文件内容


#ifndef          __STACK_H__
#define          __STACK_H__
typedef struct {
    int buf[SIZE];    //前面的数字记录到小下标的存储区里,后面的数字记录到大下标的存储区里
    int qty;          //记录栈里的数字个数
} stack;    //用来代表栈的结构体类型
//栈的初始化函数
void stack_init(stack * /*指向调用函数提供的一个代表栈的结构体存储区*/);
//栈的清理函数
void stack_deinit(stack *);
//获得数字个数的函数
int /*得到的数字个数*/stack_size(const stack *);
//判断栈是否空的函数
int /*返回值为真表示栈是空的,否则栈不是空的*/stack_empty(const stack *);
//判断栈是不是满的函数
int /*返回值为真表示栈是满的,否则栈不是满的*/stack_full(const stack *);
//向栈里加入数字的函数
int /*返回值为真表示加入成功,否则加入失败*/stack_push(stack *, int /*表示要加入的数字*/);
//从栈里获得一个数字的函数(同时把数字从栈里删除)
int /*返回值为真表示获得数字成功,为假表示失败*/stack_pop(stack *, int * /*把得到的数字记录到这个指针指向的整数类型存储区里*/);
//从栈里获得最后一个数字的函数(不会从栈里删除数字)
int /*返回值为真表示成功获得数字,为假表示没有获得数字*/stack_top(const stack *, int *);
#endif     //__STACK_H__


3、stack主函数


#include <stdio.h>
#include "01stack.h"
int main() {
    int val = 0;
    stack stk = {0};
    stack_init(&stk);
    printf("数字个数是%d\n", stack_size(&stk)/*获得栈里数字个数*/);
    printf("判断空的结果是%d\n", stack_empty(&stk));   //判断栈是否空
    printf("判断满的结果是%d\n", stack_full(&stk));    //判断栈是否满
    stack_push(&stk, 10);
    stack_push(&stk, 20);
    stack_push(&stk, 30);
    printf("数字个数是%d\n", stack_size(&stk)/*获得栈里数字个数*/);
    printf("判断空的结果是%d\n", stack_empty(&stk));   //判断栈是否空
    printf("判断满的结果是%d\n", stack_full(&stk));    //判断栈是否满
    stack_push(&stk, 40);
    stack_push(&stk, 50);
    printf("数字个数是%d\n", stack_size(&stk)/*获得栈里数字个数*/);
    printf("判断空的结果是%d\n", stack_empty(&stk));   //判断栈是否空
    printf("判断满的结果是%d\n", stack_full(&stk));    //判断栈是否满
    stack_top(&stk, &val);   //从栈里获得最后一个数字
    printf("最后一个数字是%d\n", val);
    while (1) {
        if (!stack_pop(&stk, &val)) {   //从栈里获得一个数字并把数字从栈里删除
            //当不能从栈里获得数字的时候
            break;
        }
        printf("%d ", val);
    }
    printf("\n");
    printf("数字个数是%d\n", stack_size(&stk)/*获得栈里数字个数*/);
    printf("判断空的结果是%d\n", stack_empty(&stk));   //判断栈是否空
    printf("判断满的结果是%d\n", stack_full(&stk));    //判断栈是否满
    stack_deinit(&stk);
    return 0;
}
运行结果:
数字个数是0
判断空的结果是1
判断满的结果是0
数字个数是3
判断空的结果是0
判断满的结果是0
数字个数是5
判断空的结果是0
判断满的结果是0
最后一个数字是50
50 40 30 20 10
数字个数是0
判断空的结果是1
判断满的结果是0


三、树


1、tree.c内容


#include <stdlib.h>
#include "tree.h"
//树的初始化函数
void tree_init(tree *p_tree) {
    p_tree->p_node = NULL;    //把方块里的指针设置成空指针形成一个空树(没有圆圈的树)
}
//树的清理函数
void tree_deinit(tree *p_tree) {
    //清理函数必须采用后序遍历方式处理
    if (!(p_tree->p_node)) {
        //处理树里没有节点的情况
        return ;
    }
    tree_deinit(&(p_tree/*指向最上面的方块*/->p_node/*指向最大的圆圈*/->left/*代表左子树的方块*/));     //清理左子树
    tree_deinit(&(p_tree->p_node->right));    //清理右子树
    free(p_tree->p_node);    //释放最大的圆圈
    p_tree->p_node = NULL; //把最上面方块里的指针设置成空指针
}
//在有序二叉树里查找某个数字应该插入位置的函数
tree * /*用一个方块的地址作为返回值表示找到的位置*/tree_search(const tree *p_tree, int val) {
    //采用递归函数实现查找效果
    if (!p_tree->p_node) {
        //处理树里没有节点的情况
        return (tree *)p_tree;    //把树里唯一的方块作为返回值传递给调用函数
    }
    //采用分支在根节点,左子树和右子树里
    //挑一部分继续查找
    if (p_tree->p_node->val == val) {
        //根节点里的数字就是要找的数字
        return (tree *)p_tree;   //用根节点上面的方块表示找到的位置
    }
    else if (p_tree->p_node->val > val) {
        //根节点里的数字比要找的数字大就
        //应该在左子树里继续查找
        return tree_search(&(p_tree->p_node->left), val);    //把左子树方块的地址作为第一个参数递归调用查找函数就可以在左子树里继续查找
    }
    else {
        return tree_search(&(p_tree->p_node->right), val);    //把右子树方块的地址作为第一个参数递归调用查找函数表示在右子树里继续查找
    }
}
//在有序二叉树里插入数字的函数
int tree_insert(tree *p_tree, int val) {
    node *p_node = NULL;
    tree *p_pos = tree_search(p_tree, val);    //在有序二叉树里查找要插入的位置
    if (p_pos->p_node) {
        //如果找到的方块下面有一个圆圈那这个
        //圆圈里就放着要插入的数字
        return 0;
    }
    p_node = (node *)malloc(sizeof(node));   //动态分配节点记录要插入的数字
    if (!p_node) {
        //动态分配失败的情况
        return 0;
    }
    p_node->val = val;       //把新数字记录到动态分配节点里
    p_node->left.p_node = NULL;    //动态分配节点没有左子节点
    p_node->right.p_node = NULL;   //动态分配节点也没有右子节点
    p_pos->p_node = p_node;     //把新节点挂在找到的方块下面
    return 1;
}
//以中序遍历方式处理树里每个节点的函数
void tree_miter(const tree *p_tree, pfunc_t p_func) {
    if (!p_tree->p_node) {
        //处理树为空的情况
        return ;
    }
    tree_miter(&(p_tree->p_node->left), p_func);   //把左子树方块的地址作为参数递归调用tree_miter函数处理左子树里的所有节点
    p_func(p_tree->p_node->val);   //处理根节点里的数字
    tree_miter(&(p_tree->p_node->right), p_func);  //把右子树方块的地址作为参数递归调用tree_miter函数处理右子树里的所有节点
}


2、tree.h内容


#ifndef           __TREE_H__
#define           __TREE_H__
struct node;    //告诉编译器存在一个叫做node的结构体类型
typedef struct {
    struct node *p_node;
} tree;
typedef struct node {
    int val;
    tree left;     //左子树
    tree right;    //右子树
} node;
typedef void (*pfunc_t)(int);    //创建函数指针类型名称,这种类型的函数指针都可以指向print_cb函数
//树的初始化函数
void tree_init(tree *);
//树的清理函数
void tree_deinit(tree *);
//在有序二叉树里插入数字的函数
int tree_insert(tree *, int );
//以中序遍历方式处理树里每个节点的函数
void tree_miter(const tree *, pfunc_t );
#endif          //__01TREE_H__

3、主函数内容


#include <stdio.h>
#include "tree.h"
void print_cb(int val) {
    printf("%d ", val);
}
int main() {
    tree tr = {0};
    tree_init(&tr);
    tree_insert(&tr, 50);
    tree_insert(&tr, 25);
    tree_insert(&tr, 75);
    tree_insert(&tr, 13);
    tree_insert(&tr, 37);
    tree_insert(&tr, 67);
    tree_insert(&tr, 88);
    tree_insert(&tr, 7);
    tree_miter(&tr, print_cb);   //把print_cb函数作为第二个参数调用中序遍历函数把有序二叉树里所有数字按照从小到大的顺序显示在屏幕上
    printf("\n");
    tree_deinit(&tr);
    return 0;
}
目录
相关文章
|
20天前
|
C语言
对链表使用插入排序的C语言实现示例
对链表使用插入排序的C语言实现示例
|
1月前
|
机器学习/深度学习 存储 算法
C语言栈与递归的实现讲解
C语言栈与递归的实现讲解
24 0
|
1月前
|
C语言
C语言栈的行编辑程序讲解
C语言栈的行编辑程序讲解
29 0
|
2天前
|
C语言
数据结构中顺序栈的进栈和出栈用C语言表示
数据结构中顺序栈的进栈和出栈用C语言表示
11 1
|
2天前
|
存储
线性表、链表、栈和队列的初始化
线性表、链表、栈和队列的初始化
9 1
|
1月前
|
存储 C语言 索引
在C语言中静态链表
在C语言中静态链表
17 1
|
1月前
|
存储 算法 C语言
在C语言中的动态链表
在C语言中的动态链表
9 0
|
1月前
|
前端开发 C语言
c语言中的链表
c语言中的链表
9 1
|
1月前
|
存储 C语言
C语言栈的数制转换的定义讲解
C语言栈的数制转换的定义讲解
31 0
|
1月前
|
算法
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)