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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

重学数据结构007——二叉查找树

發(fā)布時間:2023/11/29 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重学数据结构007——二叉查找树 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? 之前的博客中提到過,我學(xué)習(xí)采用的參考書是《數(shù)據(jù)結(jié)構(gòu)與算法分析——C語言描述》。這門書的組織安排與國內(nèi)廣泛實(shí)用的教材《數(shù)據(jù)結(jié)構(gòu)——C語言版》比較不同。這本書描述了一些樹和二叉樹的概念,舉例講解了什么是樹的三種遍歷之后,就開始重點(diǎn)講解二叉查找樹、平衡二叉樹、AVL樹、伸展樹、B數(shù)了。這一篇博客,重點(diǎn)學(xué)習(xí)二叉查找樹的概念和基本操作。

? ? 大家都知道,樹的定義本身就帶有遞歸性。因此,樹的很多操作都涉及到了遞歸。二叉查找樹的定義如下:

? ? 1.二叉查找樹首先是一棵二叉樹;

? ? 2.二叉查找樹除了是二叉樹外,還具有以下性質(zhì):對于樹中的任何一個節(jié)點(diǎn)X,其左子樹中的所有節(jié)點(diǎn)的關(guān)鍵字均小于X的關(guān)鍵字的值;而其右子樹中的所有關(guān)鍵字的值均大于X的關(guān)鍵字的值。下面兩棵二叉樹中,左邊的二叉樹是二叉查找樹而右邊的不是。

?

? ? 二叉查找樹的數(shù)據(jù)結(jié)構(gòu)定義如下:

  • typedef?int?ElementType;?
  • typedef?struct?TreeNode?*Position;?
  • typedef?Position?BiSearchTree;?
  • struct?TreeNode?
  • {?
  • ????ElementType?Element;?
  • ????BiSearchTree?Left,Right;?
  • };?
  • ? ? 二叉查找樹的常用操作如下:

  • BiSearchTree?MakeEmpty(BiSearchTree?Tree);?
  • Position?Find(ElementType?X,?BiSearchTree?T);?
  • Position?FindMin(BiSearchTree?T);?
  • Position?FindMax(BiSearchTree?T);?
  • BiSearchTree?Insert(ElementType?X,BiSearchTree?T);?
  • BiSearchTree?Delete(ElementType?X,?BiSearchTree?T);?
  • ? ? 二叉排序樹的操作與之前學(xué)習(xí)的一些數(shù)據(jù)結(jié)構(gòu)的操作相比,可能難理解一些。下面我們挑比較難的幾個一一講解。

    ? ? 1.二叉查找樹中查找指定的元素Find

    ? ? 二叉排序樹的性質(zhì)是二叉排序樹很多操作的基本依據(jù)。既然要查找指定元素X,先比較X與根節(jié)點(diǎn)元素的關(guān)系,如果剛好相等,直接返回啦;如果X小于根節(jié)點(diǎn)的元素值,那么去根節(jié)點(diǎn)的左子樹中查找,也就是調(diào)用Find方法,只是傳遞的參數(shù)是X和根節(jié)點(diǎn)的左子樹;如果X大于根節(jié)點(diǎn)的元素值,那么去根節(jié)點(diǎn)的右子樹中查找,也就是調(diào)用Find函數(shù),只是傳遞的參數(shù)是X和根節(jié)點(diǎn)的右子樹。

    ? ? 2.查找最小元素FindMin和最大元素FindMax

    ? ? 這兩個操作是類似的。采用迭代或者遞歸都可以實(shí)現(xiàn),查找最小元素只需要沿著左子樹訪問下去,查找最大元素則相反。下面我們會分別采用遞歸和迭代實(shí)現(xiàn)這兩個操作。

    ? ? 3.插入操作Insert

    ? ? 插入操作其實(shí)類似于查找操作,插入過過程其實(shí)就是先得找到一個合適的位置。插入其實(shí)有下面幾個情況:

    ? ? (1)如果函數(shù)傳進(jìn)來的是空樹,那么創(chuàng)建一棵樹,將其元素值設(shè)置為X。這種情況顯而易見;

    ? ? (2)如果不是空樹,那就比較根節(jié)點(diǎn)元素值和X的大小,如果X的值小于根節(jié)點(diǎn)的元素值,而此時的根節(jié)點(diǎn)的左子樹為空,那么根節(jié)點(diǎn)的左孩子就是X元素的歸宿啦;同樣的道理,如果X的值大于根節(jié)點(diǎn)的元素值,而此時根節(jié)點(diǎn)的右子樹為空,那么根節(jié)點(diǎn)的右孩子就是X元素的歸宿啦。把握住這一點(diǎn)其實(shí)基本上就能把握住這個操作了。文字描述可能比較抽象,下面看圖:

    ? ? 左邊的圖,如果要插入5,沿著樹一直找到節(jié)點(diǎn)4,這時5>4并且4的右孩子為空,那么5就是4的右孩子。右邊的圖,要想插入8,沿著樹找到9,發(fā)現(xiàn)8<9且9的左孩子為空,那么8就是9的左孩子。

    ? ? 當(dāng)然,在實(shí)現(xiàn)這樣一個過程的時候可以使用遞歸。

    ? ? 4.刪除操作Delete

    ? ? 刪除操作是我認(rèn)為最復(fù)雜最不好理解的一個操作。如果沒有仔細(xì)想明白整個過程,上來就看代碼的話可能會很暈。刪除操作分兩步:第一步是查找,找的過程就涉及元素值之間的比較。我們重點(diǎn)說找到之后的操作。假設(shè)我們找到了這個節(jié)點(diǎn),現(xiàn)在要刪除,涉及三種情況:

    ? ? (1)該節(jié)點(diǎn)是葉子。這還有什么好說的,直接刪了一了百了;

    ? ? (2)該節(jié)點(diǎn)只有一個孩子節(jié)點(diǎn)。也不復(fù)雜,讓該節(jié)點(diǎn)的父節(jié)點(diǎn)直接指向其子節(jié)點(diǎn)就行了。當(dāng)然,也別忘了回收該節(jié)點(diǎn);

    ? ? (3)該節(jié)點(diǎn)有兩個孩子:找到該節(jié)點(diǎn)右子樹中最小的節(jié)點(diǎn),將其元素值賦給該節(jié)點(diǎn),然后刪除那個最小節(jié)點(diǎn)。這種情況看圖:

    ?

    ? ? 說了半天了,下面看看完整的代碼:

  • #include?<stdio.h>?
  • #include?<stdlib.h>?
  • ?
  • typedef?int?ElementType;?
  • typedef?struct?TreeNode?*Position;?
  • typedef?Position?BiSearchTree;?
  • struct?TreeNode?
  • {?
  • ????ElementType?Element;?
  • ????BiSearchTree?Left,Right;?
  • };?
  • ?
  • //建立一顆空樹?
  • BiSearchTree?MakeEmpty(BiSearchTree?Tree)?
  • {?
  • ????if(!Tree)?
  • ????{?
  • ????????MakeEmpty(Tree->Left);?
  • ????????MakeEmpty(Tree->Right);?
  • ????????free(Tree);?
  • ????}?
  • ????return?NULL;?
  • }?
  • //二叉查找樹的Find操作?
  • Position?Find(ElementType?X,?BiSearchTree?T)?
  • {?
  • ????if(T?==?NULL)?
  • ????{?
  • ????????return?NULL;?
  • ????}?
  • ????else?
  • ????{?
  • ????????//關(guān)鍵字小于根節(jié)點(diǎn)的元素值?
  • ????????if(X?<?T->Element)?
  • ????????{?
  • ????????????return?Find(X,T->Left);?
  • ????????}?
  • ????????else?if(X?>?T->Element)?
  • ????????{?
  • ????????????return?Find(X,T->Right);?
  • ????????}?
  • ????????else?
  • ????????{?
  • ????????????return?T;?
  • ????????}?
  • ????}?
  • }?
  • //查找最小值:遞歸寫法?
  • Position?FindMin(BiSearchTree?T)?
  • {?
  • ????if(T?==?NULL)?
  • ????{?
  • ????????return?NULL;?
  • ????}?
  • ????else?
  • ????{?
  • ????????if(T->Left?==?NULL)??
  • ????????{?
  • ????????????return?T;?
  • ????????}else?
  • ????????{?
  • ????????????return?FindMin(T->Left);?
  • ????????}?
  • ????}?
  • }?
  • ?
  • //查找最大值:非遞歸寫法?
  • Position?FindMax(BiSearchTree?T)?
  • {?
  • ????if(T->Right?!=?NULL)?
  • ????{?
  • ????????while(T->Right?!=?NULL)?
  • ????????{?
  • ????????????T?=?T->Right;?
  • ????????}?
  • ????}?
  • ????return?T;?
  • }?
  • //插入元素X?
  • BiSearchTree?Insert(ElementType?X,BiSearchTree?T)?
  • {?
  • ????//當(dāng)樹為空樹時?
  • ????if(T?==?NULL)?
  • ????{?
  • ????????T?=?malloc(sizeof(struct?TreeNode));?
  • ????????if(T?==?NULL)?
  • ????????{?
  • ????????????fprintf(stderr,"Out?of?Space!!!");?
  • ????????}?
  • ????????else?
  • ????????{?
  • ????????????T->Element?=?X;?
  • ????????????T->Left?=?NULL;?
  • ????????????T->Right?=?NULL;?
  • ????????}?
  • ????}?
  • ????//樹不為空時?
  • ????else?
  • ????{?
  • ????????if(X?<?T->Element)??
  • ????????{?
  • ????????????T->Left?=?Insert(X,T->Left);?
  • ????????}?
  • ????????else?if(X?>?T->Element)??
  • ????????{?
  • ????????????T->Right?=?Insert(X,T->Right);?
  • ????????}?
  • ????????else?
  • ????????{?
  • ????????????//do?nothing!?
  • ????????}?
  • ????}?
  • ????return?T;?
  • }?
  • ?
  • //刪除節(jié)點(diǎn)X?
  • BiSearchTree?Delete(ElementType?X,?BiSearchTree?T)?
  • {?
  • ????Position?TmpCell;?
  • ????if(T==NULL)?
  • ????{?
  • ????????fprintf(stderr,"Element?does?not?exist!");?
  • ????}?
  • ????else?if(X?<?T->Element)?
  • ????{?
  • ????????T->Left?=?Delete(X,T->Left);?
  • ????}?
  • ????else?if(X?>?T->Element)?
  • ????{?
  • ????????T->Right?=?Delete(X,T->Right);?
  • ????}?
  • ????else?if(T->Left?&&?T->Right)?
  • ????{?
  • ????????TmpCell?=?FindMin(T->Right);?
  • ????????T->Element?=?TmpCell->Element;?
  • ????????T->Right?=?Delete(T->Element,T->Right);?
  • ????}?
  • ????else?
  • ????{?
  • ????????TmpCell?=?T;?
  • ????????if(T->Left?==?NULL)?
  • ????????{?
  • ????????????T?=?T->Right;?
  • ????????}?
  • ????????else?if(T->Right?==?NULL)?
  • ????????{?
  • ????????????T?=?T->Left;?
  • ????????}?
  • ????????free(TmpCell);?
  • ????}?
  • ????return?T;?
  • }?
  • ?
  • int?main(void)?
  • {?
  • ????BiSearchTree?T;?
  • ????int?index;?
  • ????int?arr[10]?=?{10,9,8,7,6,1,2,3,4,5};?
  • ????T?=?NULL;?
  • ????for(index=0;?index?<?10;?index++)?
  • ????{?
  • ????????T?=?Insert(arr[index],T);?
  • ????}?
  • ????T?=?Insert(18,T);?
  • ????T?=?Insert(15,T);?
  • ????printf("The?minimum?element?is?%d\n",FindMin(T)->Element);?
  • ????printf("The?maxmium?element?is?%d\n",FindMax(T)->Element);?
  • ????return?0;?
  • }?
  • ?

    ?

    ?

    ?

    ?

    ?

    ?

    轉(zhuǎn)載于:https://blog.51cto.com/wawlian/722244

    總結(jié)

    以上是生活随笔為你收集整理的重学数据结构007——二叉查找树的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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