日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

二叉查找树的C语言实现(一)

發(fā)布時(shí)間:2025/3/15 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉查找树的C语言实现(一) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是二叉查找樹?

二叉查找樹(Binary Search Tree),也稱有序二叉樹(ordered binary tree),排序二叉樹(sorted binary tree),是指一棵空樹或者具有下列性質(zhì)的二叉樹:

  • 若任意節(jié)點(diǎn)的左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值;
  • 若任意節(jié)點(diǎn)的右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值;
  • 任意節(jié)點(diǎn)的左、右子樹也分別為二叉查找樹;
  • 沒有鍵值相等的節(jié)點(diǎn)(no duplicate nodes)。
  • 好的,我們來(lái)定義一個(gè)結(jié)構(gòu)體, struct bnode_info {struct bnode_info *parent;struct bnode_info *lchild;struct bnode_info *rchild; };怎么沒有數(shù)據(jù)域呢?模仿內(nèi)核鏈表,我們把這個(gè)節(jié)點(diǎn)嵌入到大的結(jié)構(gòu)體里。 static inline void bnode_init(struct bnode_info *bnode) {bnode->parent = NULL;bnode->lchild = NULL;bnode->rchild = NULL; }節(jié)點(diǎn)的初始化函數(shù),為下文做準(zhǔn)備。
    struct data_info {int data;struct bnode_info bnode; };這個(gè)是測(cè)試用的,可以看到,把節(jié)點(diǎn)嵌入了進(jìn)去。
    static int bnode_cmp(struct bnode_info *a, struct bnode_info *b) {struct data_info *pa = list_entry(a, struct data_info, bnode);struct data_info *pb = list_entry(b, struct data_info, bnode);return pa->data - pb->data; }這是比較函數(shù),關(guān)于list_entry宏,前面的博文已經(jīng)說(shuō)了,這里不贅述。
    struct btree_info {struct bnode_info *root; //指向樹根int (*key_cmp)(struct bnode_info *a, struct bnode_info *b);void (*push)(struct bnode_info *bnode, struct btree_info *info);int (*del)(struct bnode_info *bnode, struct btree_info *info);struct bnode_info *(*find)(struct bnode_info *bnode, struct btree_info *info);void (*pre_order)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));void (*in_order)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));void (*post_order)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));//非遞歸遍歷void (*pre_order_norecur)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));void (*in_order_norecur)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));void (*post_order_norecur)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));void (*level_order)(struct btree_info *info, void (*todo)(struct bnode_info *bnode));size_t (*get_depth)(const struct btree_info *info);int (*is_empty)(const struct btree_info *info); };這里定義了很多方法,我們先不管,只要知道里面有個(gè)指針,指向樹根就可以了。
    static int btree_is_empty(const struct btree_info *btree) {return btree->root == NULL; }如果樹為空,那就是連樹根都沒有了。
    下面進(jìn)入正題,說(shuō)把一個(gè)元素插入一棵樹。 分析:1.這棵樹是空的。那問(wèn)題就簡(jiǎn)單了,這個(gè)節(jié)點(diǎn)就是樹根。 ? ?2.這棵樹不空。那就需要從樹根查找。把新元素和樹根比一比,小了就繼續(xù)和樹根的左孩子比,大了就繼續(xù)和樹根的右孩子比(假設(shè)不存在相等的情況),......,如果左孩子或者右孩子為空,那就是找到位置了,讓這個(gè)新元素成為孩子就可以了。注意,這里我們不用遞歸,用迭代。 static void btree_push2(struct bnode_info *bnode, struct btree_info *info) {assert(bnode != NULL && info != NULL);bnode_init(bnode);//[1].空樹if (btree_is_empty(info)) {info->root = bnode;return;}//[2].非空樹struct bnode_info *cur = info->root;struct bnode_info *parent = NULL;int flag = 0;while (cur != NULL) {parent = cur; if (info->key_cmp(bnode, cur) >= 0) {//右cur = cur->rchild;flag = 1;}else {//左cur = cur->lchild;flag = 0;}} if(flag==0) parent->lchild=bnode;elseparent->rchild=bnode;bnode->parent = parent;}

    為了驗(yàn)證對(duì)錯(cuò),我們要寫個(gè)遍歷樹的方法。看看先序遍歷-遞歸版本,(先樹根,然后左子樹,最后右子樹) static void __pre_order(struct bnode_info *bnode,void (*todo)(struct bnode_info *bnode)) {if (bnode != NULL) {todo(bnode);__pre_order(bnode->lchild, todo);__pre_order(bnode->rchild, todo);} }static void btree_pre_order(struct btree_info *info,void (*todo)(struct bnode_info *bnode)) {__pre_order(info->root, todo); }
    void print_node(struct bnode_info *node) {struct data_info *pa = list_entry(node, struct data_info, bnode);printf("%d ", pa->data); }這個(gè)是打印用的,到時(shí)候傳給todo。
    測(cè)試函數(shù): int main() {struct data_info s[]={{50},{24},{80},{16},{26},{5}};struct btree_info *btree = (struct btree_info *)malloc(sizeof(struct btree_info));assert(btree != NULL);btree_init(btree, bnode_cmp);int i;for (i = 0; i < sizeof s/ sizeof *s; ++i) {btree->push(&s[i].bnode, btree);}//遍歷printf("--pre_order--\n");btree->pre_order(btree, print_node);printf("\n");

    我們先看看運(yùn)行結(jié)果:

    --pre_order--

    50 24 16 5 26 80?


    接著說(shuō)插入,前面是非遞歸方法。這次我們用遞歸。思路很簡(jiǎn)單,把要插入的節(jié)點(diǎn),和樹根比,如果樹根為空,那么這個(gè)節(jié)點(diǎn)就成為樹根;如果比樹根小,就和樹根的左孩子比(左孩子可以看成是新的樹根);如果比樹根大,就和樹根的右孩子比。這里需要注意的是,假設(shè)比樹根小,那么就和樹根的左孩子比,假設(shè)傳進(jìn)來(lái)的參數(shù)是新節(jié)點(diǎn)和左孩子,我們發(fā)現(xiàn)左孩子為NULL,怎么辦呢?當(dāng)然應(yīng)該把新節(jié)點(diǎn)的地址寫入這里,為了改寫NULL,我們就應(yīng)該知道這個(gè)域的地址,這里就引入了二級(jí)指針。也就是說(shuō),我們的函數(shù)設(shè)計(jì)的時(shí)候,參數(shù)是新節(jié)點(diǎn)的地址,和樹根的二級(jí)指針。
    static void __push(struct bnode_info *bnode, struct bnode_info **pnode, int (*cmp)(struct bnode_info *a, struct bnode_info *b)) {if (*pnode == NULL){bnode_init(bnode);*pnode = bnode; }else{ if (cmp(bnode, *pnode) > 0)__push(bnode, &(*pnode)->rchild,cmp);else __push(bnode, &(*pnode)->lchild,cmp); } }void btree_push_recursion(struct bnode_info *bnode, struct btree_info *info) {assert(bnode != NULL && info != NULL);__push(bnode, &info->root,info->key_cmp);//第二個(gè)參數(shù)是二級(jí)指針 }
    總結(jié)一下,這篇文章我們說(shuō)了什么?1.節(jié)點(diǎn)的插入(遞歸和非遞歸)2.先序遍歷(遞歸版本) 下次我們接著說(shuō)。









    與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖

    總結(jié)

    以上是生活随笔為你收集整理的二叉查找树的C语言实现(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。