1. 程式人生 > >手寫二叉樹的基本操作

手寫二叉樹的基本操作

本題題目來源是:

老實說,寫二叉樹的基本操作寫的我心慌意亂,主要原因是總感覺遞迴學的不夠深入。
在昨天與前天再次沉思遞迴的奧祕後,我感覺到了力量。
然而還是不夠自信,於是在網上找別人的寫法,粗粗讀了幾篇,具體的操作都很簡單,但是別人寫的我卻死活走不通,我想,是時候自己動手造青蛙學習而不是看著青蛙了。

於是,有了下面這個冗長的各種遞迴寫法的程式碼:
如果過段時間我還看得懂,我就來寫程式碼的解釋,今天下午的兩個小時都寫這個了。。
但是,很爽~

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct TNode *
Position; typedef Position BinTree; struct TNode{ ElementType Data; BinTree Left; BinTree Right; }; // 實現二叉樹的五種操作 BinTree Insert( BinTree BST, ElementType X ); BinTree Delete( BinTree BST, ElementType X ); Position Find( BinTree BST, ElementType X ); Position FindMin( BinTree BST ); Position FindMax( BinTree BST ); BinTree SubTreeInsert(BinTree BST, ElementType X); Position LocateParent(BinTree BST, ElementType X); BinTree DeleteNode(BinTree BST, Position parent
, Position node); void PreorderTraversal(BinTree BT ) /* 先序遍歷*/ { if(BT != NULL) { printf("%d ",BT->Data ); PreorderTraversal(BT->Left); //遍歷左子樹 PreorderTraversal(BT->Right); //遍歷右子樹 } } void InorderTraversal( BinTree BT )/* 中序遍歷*/ { if(BT) { InorderTraversal(BT->
Left); printf("%d ",BT->Data ); InorderTraversal(BT->Right); } } //測試程式 int main() { BinTree BST, MinP, MaxP, Tmp; ElementType X; int N, i; BST = NULL; scanf("%d", &N); for ( i=0; i<N; i++ ) { scanf("%d", &X); BST = Insert(BST, X); } printf("Preorder:"); PreorderTraversal(BST); printf("\n"); MinP = FindMin(BST); MaxP = FindMax(BST); scanf("%d", &N); for( i=0; i<N; i++ ) { scanf("%d", &X); Tmp = Find(BST, X); if (Tmp == NULL) printf("%d is not found\n", X); else { printf("%d is found\n", Tmp->Data); if (Tmp==MinP) printf("%d is the smallest key\n", Tmp->Data); if (Tmp==MaxP) printf("%d is the largest key\n", Tmp->Data); } } scanf("%d", &N); for( i=0; i<N; i++ ) { scanf("%d", &X); BST = Delete(BST, X); } printf("Inorder:"); InorderTraversal(BST); printf("\n"); return 0; } // 遞迴版本的插入演算法 BinTree Insert(BinTree BST, ElementType X) { //pre:X不在樹中 //post:X被加入到樹中 if(BST == NULL) //空樹 { Position node = (Position)malloc(sizeof(struct TNode)); node->Left = NULL; node->Right = NULL; node->Data = X; BST = node; return BST; } if(X == BST->Data) { return NULL; } if(X < BST->Data) { BST->Left = Insert(BST->Left,X);//非常重要的是BST->Left = xx,我開始總是寫成BST = Insert(BST->Left,X); } else { BST->Right = Insert(BST->Right,X); } return BST; } BinTree DeleteNode(BinTree BST, Position parent, Position node) { // 進來的node不為空 // Case 1:葉子結點 if(node->Left == NULL && node->Right == NULL) { if(parent == NULL) //根結點 { BST = NULL; free(node); } else if((parent->Left) && parent->Left->Data == node->Data)//父結點是左手牽著此結點,任何時刻需要判斷左、右指標是否存在才能去索引結點值 { parent->Left = NULL; free(node);// 釋放這個葉子結點 } else { parent->Right = NULL; free(node);// 釋放這個葉子結點 } } // Case 2:有一個孩子,孩子的爺爺就是parent結點,因為parent是待刪除結點的爸爸,待刪除結點是孩子的爸爸 else if((node->Left == NULL && node->Right) || (node->Left && node->Right == NULL)) { if(node->Left)//還有個左孩子 { if(parent == NULL) // 待刪除的node是根節點 { BST = node->Left; // 將node的左孩子提升為根即可 } else if((parent->Left) && parent->Left->Data == node->Data)//爺爺的左手牽著爸爸,現在牽著孫子 { parent->Left = node->Left; } else { parent->Right = node->Left; } } else //還有右孩子 { if(parent == NULL) // 待刪除的node是根節點 { BST = node->Right; // 將node的左孩子提升為根即可 } else if((parent->Left) && parent->Left->Data == node->Data)//爺爺的左手牽著爸爸,現在牽著孫子 { parent->Left = node->Right; } else { parent->Right = node->Right; } } } // Case 3: 有兩個孩子呢! else { //首先找到待刪除結點的右子樹的最小結點 Position rMin = FindMin(node->Right); node->Data = rMin->Data; //待刪除結點的值替換為右子樹的最小值 // 刪除rMin這個結點:rMin結點一定無左孩子 parent = LocateParent(BST->Right,rMin->Data); BST = DeleteNode(BST,parent,rMin); } return BST; } // 函式Delete將X從二叉搜尋樹BST中刪除,並返回結果樹的根結點指標;如果X不在樹中,則列印一行Not Found並返回原樹的根結點指標; BinTree Delete( BinTree BST, ElementType X) { // 均需要跟蹤父節點 // 如果刪除的是葉子結點,直接刪就好了:交給爺爺! // 如果刪除的結點有左孩子但是沒有右孩子或者有右孩子沒有左孩子,直接讓這個孩子交給它爺爺,它爺爺哪隻手拽著它爸爸,現在就用哪隻手拽它 // 如果刪除的結點有左孩子還有右孩子,這個需要從要刪除的結點的右子樹中找到一個最小的,用這個值填充待刪除結點的父親,然後刪掉這個最小結點,最小結點是葉子結點 // Position node = Find(BST,X); //找到待刪除的結點,可以是根結點 if(node == NULL) { printf("Not Found\n"); return BST; } else //X在樹中 { Position parent = LocateParent(BST,X); //找到X的父親結點,如果parent是NULL則,表示刪除的是根結點 BST = DeleteNode(BST,parent,node); } return BST; } Position LocateParent(BinTree BST, ElementType X) // 找到結點值是X的父結點,返回結點的指標 { if(BST->Data == X) //X是根結點 { BST = NULL; } if(BST) { if(((BST->Left) && BST->Left->Data == X) || ((BST->Right) && BST->Right->Data == X)) { return BST; } if(X < BST->Data) { BST = LocateParent(BST->Left,X); } else { BST = LocateParent(BST->Right,X); } } return BST; } // 各種尋找都是遞迴的巧妙利用 // 函式Find在二叉搜尋樹BST中找到X,返回該結點的指標;如果找不到則返回空指標; Position Find( BinTree BST, ElementType X ) //這裡的BST不會改變原本的根結點表達的值,這是根的副本 { //這個在Delete中也要呼叫 if(BST) { if(X == BST->Data) //如果元素值相同,返回這個結點指標 { return BST; } if(X < BST->Data) // 往左子樹尋找 { BST = Find(BST->Left,X); } else { BST = Find(BST->Right,X); } } return BST; } // 函式FindMin返回二叉搜尋樹BST中最小元結點的指標; // 思路:一路向左 Position FindMin( BinTree BST ) { if(BST == NULL) { return NULL; } if(BST->Left == NULL) //這種上來就訪問Left指標,需要小心,因為不一定存在:BST本身不存在時候 { return BST; // 此時BST指代的元素值是最左邊的值 } else { BST = FindMin(BST->Left); } return BST; } // 函式FindMax返回二叉搜尋樹BST中最大元結點的指標。 // 思路:一路向右 Position FindMax( BinTree BST ) { if(BST == NULL) { return NULL; } if(BST->Right == NULL) { return BST; } else { BST = FindMax(BST->Right); } return BST; }

測試結果是:
這裡寫圖片描述

這是一次不參考別人程式碼,只用基本的遞迴知識以及對樹形結構的理解寫出來的二叉樹的五種操作的程式碼,其中,另外實現了兩種LocateParent函式用於找到指定數值結點的父結點,DeleteNode是一個輔助函式。不直接寫在Delete中是為了方便遞迴呼叫。

老實說,這段程式碼寫了兩個下午,共用時4個多小時,不加中間零碎時間的思考。寫的我幾乎要放棄,每次一個bug出現,單步跟蹤給了我繼續修正下去的勇氣。

我演算法功底一直停留在紙上談兵階段,真正動手才知道我差在哪裡。

不斷學習。

以上。

相關推薦

基本操作

本題題目來源是: 老實說,寫二叉樹的基本操作寫的我心慌意亂,主要原因是總感覺遞迴學的不夠深入。 在昨天與前天再次沉思遞迴的奧祕後,我感覺到了力量。 然而還是不夠自信,於是在網上找別人的寫法,粗粗讀了幾篇,具體的操作都很簡單,但是別人寫的我卻死活走不通,

基本操作

arch 非遞歸 alt pro stack depth 隊列 步驟 read 廣度優先搜索 1、把根節點入隊列; 2、如果隊列非空,出隊,再依次將左子樹入隊、右子樹入隊; 3、重復步驟2,直到隊列為空。 void BreadFirstSearch(TreeNode *ro

線索基本操作的實現

2018-11-18-18:25:23 一:二叉樹 1.二叉樹的性質   ①:在二叉樹的第i層上至多有pow(2,i-1)個結點(i>=1)。   ②:深度為k的二叉樹至多有pow(2,k)-1個結點(k>=1)。   ③:對任何一顆二叉樹T,如果其終端結點的個數為n0,度為2的結點數為

#五年經驗程式設計師面試,被要求,給的薪資卻是兩年程度!網友:進去擰螺絲?

現在很多公司在招聘開發崗位的時候,都會事先在招聘資訊中註明面試者應當具備的知識技能,而且在面試的過程中,有部分對於技能掌握程度有嚴格要求的公司還會要求面試者手寫程式碼,這個環節很考驗面試者的基礎功底和實力!如果能夠通過那自然是達到了面試的要求,那麼給的薪資自然不會低到那裡去。 如果有想學習jav

【資料結構】基本操作

文章目錄 BinaryTree.h BinaryTree.c Test.c 棧和佇列的相關函式: 棧:https://blog.csdn.net/weixin_41892460/article/details/82

C語言-基本操作以及搜尋基本操作

功能 二叉樹操作: 建立二叉樹 遍歷二叉樹(前序,中序,後續) 計算高度 計算結點數目 清空二叉樹 空樹判斷 二叉搜尋樹操作: 插入 最值(最大值,最小值) 刪除 程式碼 #include &l

c++學習筆記—基本操作的實現

用c++語言實現的二叉樹基本操作,包括二叉樹的建立、二叉樹的遍歷(包括前序、中序、後序遞迴和非遞迴演算法)、求二叉樹高度,計數葉子節點數、計數度為1的節點數等基本操作。 IDE:vs2013 具體實現程式碼如下: #include "stdafx.h" #include

超全C語言基本操作及講解

今天刷LeetCode上的題的時候,做到了關於二叉樹的題,於是決定把這一塊的知識整理一下。1、二叉樹的定義二叉樹通常以結構體的形式定義,如下,結構體內容包括三部分:本節點所儲存的值、左孩子節點的指標、右孩子節點的指標。這裡需要注意,子節點必須使用指標,就像我們定義結構體連結串

實驗四 基本操作的實現

實現鏈式儲存建立,遞迴先序 中序 後序遍歷,葉子結點數,數的結點總數,交換左右子樹 #include <stdio.h> #include <stdlib.h> #include <malloc.h> int cnt; //結點宣告,資

基本操作實現及總結(適合複習)

本文包含以下內容 1 ,二叉樹三種建立 前序遞迴 表示式非遞迴 孩子兄弟表示式非遞迴 2,遍歷 三種遍歷的遞迴與非遞迴實現(前中後序) 層次遍歷(普通二叉樹,孩子兄弟連結串列)

前端面試題之排序

前端面試題之手寫二叉排序樹 二叉排序樹:每個節點的左節點都比根節點小,右節點都比根節點大 function TreeNode(data, left, right) { //節點結構 this.val = data; this.left = left; this

排序(查詢、搜尋)

二叉排序樹(查詢樹,搜尋樹)或者是一顆空樹,或者是一顆具有如下性質的樹: 1)若左子樹不為空,那麼左子樹上面的所有節點的關鍵字值都比根節點的關鍵字值小 2)若右子樹不為空,那麼右子樹上面的所有節點的關鍵字值都比根節點的關鍵字值大 3)左右子樹都為二叉樹 4)沒有重複值(這一點在實際中可以忽略)

基本概念

相同 完全二叉樹 算法 平衡 都在 最大值 fma word 特殊 1. 高度:樹T所有節點深度的最大值,節點V對應子樹高度為該節點的高度,根節點高度為整棵樹的高度 2.深度:節點V到根節點R的唯一路徑所經過的數目稱為V的深度 3.huffman編碼:構造出的帶權平均深

基礎操作

rep unsigned signed ace 輸出 nod inf dtree bit #include<bits/stdc++.h> #define de(x) cout<<#x<<"="<<x<<endl;

基本概念(滿、完全,滿的遍歷)

1. 二叉樹 二叉樹是每個節點最多有兩個子樹的樹結構。它有五種基本形態:二叉樹可以是空集;根可以有空的左子樹或右子樹;或者左、右子樹皆為空。 性質1:二叉樹第i層上的結點數目最多為 2{i-1} (i≥1)。性質2:深度為k的二叉樹至多有2{k}-1個結點(k≥1)

今日分資料結構作業:簡單操作

又是一次非常有趣(sangxinbingkuang)的作業。 這麼簡單的作業居然寫了一下午,我也是醉了。 看來下次要調整好狀態再寫作業了QAQ。 先看實驗要求: 後三道題懶得寫了,就不發要求了/滑稽。 程式碼(附帶詳細註釋): import java.util.*;

基本運算

#include <stdio.h> #include <stdlib.h> typedef struct node { char data; struct node* lchild,*rchild; }BSTree; void initiate(BSTree

1001:操作——遍歷2

1001:二叉樹的操作——遍歷2 Time/Memory Limit:1000 MS/32768 K  Submitted: 69 Accepted: 47  Problem Description 按照給定的擴充套件二叉樹前序遍歷序

基本實現(包含main方法)

所用編譯器;Devc++(有些編譯器編譯不了,建議使用Devc++) 所用語言:C語言 邏輯結構:非線性結構 儲存結構:鏈式儲存結構 寫在前面:學習二叉樹之前也有找過一些學習資料,資料結構的書,部落格文章,但是都大概講述的是方法,並沒有給出完整的且比較適合初學者的,今天剛剛學習了二叉

資料結構之基本功能的實現

二叉樹的各種性質在這裡不再重複,本文實現二叉樹的基本操作,包括建立、前序輸出、中序輸出、後序輸出、刪除二叉樹、葉子結點個數、葉子節點的值、交換左右子樹 1.首先建立結構體: typedef struct Tree_Node{ char ch; struct