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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

二叉搜索树的算法实现

發(fā)布時間:2025/4/5 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 二叉搜索树的算法实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 1 二叉搜索樹簡介
    • 2 二叉搜索樹的算法實(shí)現(xiàn)
      • 2.1 節(jié)點(diǎn)結(jié)構(gòu)體的定義
      • 2.2 二叉搜索樹插入節(jié)點(diǎn)
      • 2.3 二叉搜索樹刪除結(jié)點(diǎn)
      • 2.4 二叉搜索樹搜索
      • 2.5 二叉搜索樹的遍歷

1 二叉搜索樹簡介

當(dāng)我們要在一組數(shù)中要找到 26?你該怎么找?

答案: 從左至右 或 從右至左遍歷一次,找到這個數(shù)字。

當(dāng)我們把數(shù)據(jù)進(jìn)行排序(按照從小到大的順序排列)后,再查找相應(yīng)的這條記錄?還是用上面的方法嗎?

答案:最快的方式,是采用折半法(俗稱二分查找)。

思考: 當(dāng)我們有新的數(shù)據(jù)加進(jìn)來,或者刪除其中的一條記錄,為了保障查找的效率,我們?nèi)匀灰U蠑?shù)組有序,但是,會碰到我們講順序表時的問題,涉及到大量數(shù)據(jù)的移動!在插入和刪除操作上,就需要耗費(fèi)大量的時間(需進(jìn)行元素的移位),能否有一種既可以使得插入和刪除效率不錯,又可高效查找的數(shù)據(jù)結(jié)構(gòu)和算法呢?

拋磚: 首先解決一個問題,插入時不移動元素,我們可以想到鏈表,但是要保證其有序的話,首先得遍歷鏈表尋找合適的位置,那么又如何高效的查找合適的位置呢,能否可以像二分一樣,通過一次比較排除一部分元素?

引玉: 那么我們可以用二叉樹的形式,以數(shù)據(jù)集第一個元素為根節(jié)點(diǎn),之后將比根節(jié)點(diǎn)小的元素放在左子樹中,將比根節(jié)點(diǎn)大的元素放在右子樹中,在左右子樹中同樣采取此規(guī)則。那么在查找 x 時,若 x 比根節(jié)點(diǎn)小可以排除右子樹所有元素,去左子樹中查找(類似二分查找),這樣查找的效率非常好,而且插入的時間復(fù)雜度為 O(h),h 為樹的高度,較 O(n)來說效率提高不少。故二叉搜索樹用作一些查找和插入使用頻率比較高的場景。


二叉樹一般采用鏈?zhǔn)酱鎯Ψ绞?#xff1a;每個結(jié)點(diǎn)包含兩個指針域,指向兩個孩子結(jié)點(diǎn),還包含一個數(shù)據(jù)域,存儲結(jié)點(diǎn)信息。


2 二叉搜索樹的算法實(shí)現(xiàn)

2.1 節(jié)點(diǎn)結(jié)構(gòu)體的定義

#define MAX_NODE 1024#define isLess(a, b) (a<b) #define isEqual(a, b) (a==b)typedef int ElemType;typedef struct _Bnode{ElemType data; //元素類型struct _Bnode *lchild, *rchild;//指向左右孩子節(jié)點(diǎn) }Bnode, *Btree;

2.2 二叉搜索樹插入節(jié)點(diǎn)

將要插入的結(jié)點(diǎn) e,與節(jié)點(diǎn) root 節(jié)點(diǎn)進(jìn)行比較,若小于則去到左子樹進(jìn)行比較,若大于則去到右子樹進(jìn)行比較,重復(fù)以上操作直到找到一個空位置用于放置該新節(jié)點(diǎn)。

bool InsertBtree(Btree **root, Bnode *node){Bnode *tmp = NULL;Bnode *parent = NULL;if(!node){return false;}else {//清空新節(jié)點(diǎn)的左右子樹node->lchild = NULL;node->rchild = NULL;}if(*root){//存在根節(jié)點(diǎn)tmp= *root;}else{ //不存在根節(jié)點(diǎn)*root = node;return true;}while(tmp != NULL){parent = tmp;//保存父節(jié)點(diǎn)printf("父節(jié)點(diǎn): %d\n", parent->data);if(isLess(node->data,tmp->data)){tmp = tmp->lchild;}else{tmp = tmp->rchild;}}//若該樹為空樹,則直接將 node 放置在根節(jié)點(diǎn)上if(isLess(node->data, parent->data)){//找到空位置后,進(jìn)行插入parent->lchild = node;}else{parent->rchild = node;}return true; }

2.3 二叉搜索樹刪除結(jié)點(diǎn)

將要刪除的節(jié)點(diǎn)的值,與節(jié)點(diǎn) root 節(jié)點(diǎn)進(jìn)行比較,若小于則去到左子樹進(jìn)行比較,若大于則去到右子樹進(jìn)行比較,重復(fù)以上操作直到找到一個節(jié)點(diǎn)的值等于刪除的值,則將此節(jié)點(diǎn)刪除。刪除時有 4 中情況須分別處理:

  • 刪除節(jié)點(diǎn)不存在左右子節(jié)點(diǎn),即為葉子節(jié)點(diǎn),直接刪除。
  • 刪除節(jié)點(diǎn)存在左子節(jié)點(diǎn),不存在右子節(jié)點(diǎn),直接把左子節(jié)點(diǎn)替代刪除節(jié)點(diǎn)。
  • 刪除節(jié)點(diǎn)存在右子節(jié)點(diǎn),不存在左子節(jié)點(diǎn),直接把右子節(jié)點(diǎn)替代刪除節(jié)點(diǎn)。
  • 刪除節(jié)點(diǎn)存在左右子節(jié)點(diǎn),則取左子樹上的最大節(jié)點(diǎn)或右子樹上的最小 節(jié)點(diǎn)替換刪除節(jié)點(diǎn)。
  • 代碼如下:

    /************************ * 采用二叉搜索樹上最大的結(jié)點(diǎn) *************************/ int findMax(Btree* root) {assert(root!=NULL);//方式一 采用遞歸/*if(root->rchild==NULL){return root->data;}return findMax(root->rchild);*///方式二 采用循環(huán)while(root->rchild){root = root->rchild;}return root->data; }/************************ * 采用遞歸方式刪除結(jié)點(diǎn) *************************/```c Btree* DeleteNode(Btree* root, int key) {if(root==NULL)return NULL;//沒有找到刪除節(jié)點(diǎn)if(root->data > key){root->lchild = DeleteNode(root->lchild, key);return root;}if(root->data < key){root->rchild = DeleteNode(root->rchild, key);return root;}//刪除節(jié)點(diǎn)不存在左右子節(jié)點(diǎn),即為葉子節(jié)點(diǎn),直接刪除if(root->lchild==NULL && root->rchild==NULL)return NULL;//刪除節(jié)點(diǎn)只存在右子節(jié)點(diǎn),直接用右子節(jié)點(diǎn)取代刪除節(jié)點(diǎn)if(root->lchild==NULL && root->rchild!=NULL)return root->rchild;//刪除節(jié)點(diǎn)只存在左子節(jié)點(diǎn),直接用左子節(jié)點(diǎn)取代刪除節(jié)點(diǎn)if(root->lchild!=NULL && root->rchild==NULL)return root->lchild;//刪除節(jié)點(diǎn)存在左右子節(jié)點(diǎn),直接用左子節(jié)點(diǎn)最大值取代刪除節(jié)點(diǎn)int val = findMax(root->lchild);root->data=val;root->lchild = DeleteNode(root->lchild,val);return root; }

    2.4 二叉搜索樹搜索

    /************************ * 采用遞歸方式查找結(jié)點(diǎn) *************************/ Bnode* queryByRec(Btree *root, ElemType e){if (root == NULL || isEqual(root->data, e)){return root;} else if(isLess(e, root->data)) {return queryByRec(root->lchild, e);} else {return queryByRec(root->rchild, e);} }/** * 使用非遞歸方式查找結(jié)點(diǎn) */ Bnode* queryByLoop(Bnode *root, int e){while(root != NULL && !isEqual(root->data, e)){if(isLess(e, root->data)){root = root->lchild;}else{root = root->rchild;}}return root; }

    2.5 二叉搜索樹的遍歷

    二叉樹的遍歷是指從根結(jié)點(diǎn)出發(fā),按照某種次序依次訪問所有結(jié)點(diǎn),使得每個結(jié)點(diǎn)僅被訪問一次。共分為四種方式:

    • 前序遍歷。
    • 中序遍歷。
    • 后序遍歷。
    • 層次遍歷。

    前序遍歷 : 先訪問根節(jié)點(diǎn),然后前序遍歷左子樹,再前序遍歷右子樹。


    代碼如下:

    /************************ * 采用遞歸方式實(shí)現(xiàn)前序遍歷 *************************/ void PreOrderRec(Btree *root) {if (root == NULL){return;}printf("- %d -", root->data);preOrderRec(root->lchild);preOrderRec(root->rchild); }/* 前序遍歷 - 非遞歸方式實(shí)現(xiàn) 具體過程: 首先申請一個新的棧,記為 stack; 將頭結(jié)點(diǎn) head 壓入 stack 中; 每次從 stack 中彈出棧頂節(jié)點(diǎn),記為 cur,然后打印 cur值,如果 cur 右孩子不為空,則將右孩子壓入棧中;如果 cur 的左孩子不為空,將其壓入 stack 中; 重復(fù)步驟 3,直到 stack 為空. */ void PreOrder(Btree *root) {Bnode cur ;if (root == NULL){return;}SqStack stack;InitStack(stack);PushStack(stack, *root); //頭節(jié)點(diǎn)先入棧while (!(IsEmpty(stack))) //棧為空,所有節(jié)點(diǎn)均已處理{PopStack(stack, cur); //要遍歷的節(jié)點(diǎn)printf("- %d -", cur.data);if (cur.rchild != NULL){PushStack(stack, *(cur.rchild)); //右子節(jié)點(diǎn)先入棧,后處理}if (cur.lchild != NULL){PushStack(stack, *(cur.lchild)); //左子節(jié)點(diǎn)后入棧,接下來先處理}}DestroyStack(stack); }

    另一種版本的實(shí)現(xiàn):

    void BinarySortTreePrintFrontRecursive(BinarySortNode* root) {if (!root) return;cout << root->e << endl;BinarySortTreePrintFrontRecursive(root->lChild);BinarySortTreePrintFrontRecursive(root->rChild); }void BinarySortTreePrintFront(BinarySortTree* tree) {if (!tree) return;BinarySortNode* node = tree;stack<BinarySortNode*> nodeStack;while ((node != NULL) || (nodeStack.size() > 0)){if (node != NULL){cout << node->e << endl;nodeStack.push(node);node = node->lChild;}else{node = nodeStack.top();nodeStack.pop();node = node->rChild;}} }

    中序遍歷: 先訪問根節(jié)點(diǎn)的左子樹,然后訪問根節(jié)點(diǎn),最后遍歷右子樹。

    void BinarySortTreePrintMiddleRecursive(BinarySortNode* root) {if (!root) return;BinarySortTreePrintMiddleRecursive(root->lChild);cout << root->e << endl;BinarySortTreePrintMiddleRecursive(root->rChild); }void BinarySortTreePrintMiddle(BinarySortNode* tree) {if (!tree) return;BinarySortNode* node = tree;stack<BinarySortNode*> nodeStack;while ((node != NULL) || (nodeStack.size() > 0)){if (node != NULL){nodeStack.push(node);node = node->lChild;}else{node = nodeStack.top();nodeStack.pop();cout << node->e << endl;node = node->rChild;}} }

    后序遍歷: 從左到右,先葉子后節(jié)點(diǎn)的方式遍歷訪問左右子樹,最后訪問根節(jié)點(diǎn)。

    void BinarySortTreePrintTailRecursive(BinarySortNode* root) {if (!root) return;BinarySortTreePrintTailRecursive(root->lChild);BinarySortTreePrintTailRecursive(root->rChild);cout << root->e << endl; }void BinarySortTreePrintTail(BinarySortNode* tree) {if (!tree) return;BinarySortNode* node = tree;stack<BinarySortNode*> nodeStack;stack<BinarySortNode*> output;while ((node != NULL) || (nodeStack.size() > 0)){if (node != NULL){nodeStack.push(node);output.push(node);node = node->rChild;}else{node = nodeStack.top();nodeStack.pop();node = node->lChild;}}while (!output.empty()){cout << output.top()->e << endl;output.pop();} }

    層序遍歷: 從根節(jié)點(diǎn)從上往下逐層遍歷,在同一層,按從左到右的順序?qū)?jié)點(diǎn)逐個訪問。

    void BinarySortTreePrintLevel(BinarySortNode* tree) {if (!tree) return;BinarySortNode* node = tree;queue<BinarySortNode*> nodeQueue;nodeQueue.push(node);while (!nodeQueue.empty()){node = nodeQueue.front();nodeQueue.pop();cout << node->e << endl;if (node->lChild != NULL){nodeQueue.push(node->lChild);}if (node->rChild != NULL){nodeQueue.push(node->rChild);}} }

    參考資料:

  • C/C++從入門到精通-高級程序員之路【奇牛學(xué)院】
  • 總結(jié)

    以上是生活随笔為你收集整理的二叉搜索树的算法实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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