1. 程式人生 > >常見基本資料結構——樹,二叉樹,二叉查詢樹,AVL樹

常見基本資料結構——樹,二叉樹,二叉查詢樹,AVL樹

常見資料結構——樹

處理大量的資料時,連結串列的線性時間太慢了,不宜使用。在樹的資料結構中,其大部分的執行時間平均為O(logN)。並且通過對樹結構的修改,我們能夠保證它的最壞情形下上述的時間界。

樹的定義有很多種方式。定義樹的自然的方式是遞迴的方式。一棵樹是一些節點的集合,這個集合可以是空集,若非空集,則一棵樹是由根節點r以及0個或多個非空子樹T1,T2,T3,......,Tk組成,這些子樹中每一棵的根都有來自根r的一條有向的邊所連線。

從遞迴的定義中,我們發現一棵樹是N個節點和N-1條邊組成的,每一個節點都有一條邊連線父節點,但是根節點除外。

具有相同父親的節點為兄弟,類似的方法可以定義祖父和孫子的關係。

從節點n1到nk的路徑定義為節點n1,n2,...,nk的一個序列,並且ni是ni+1的父親。這個路徑的長是路徑上的邊數,即k-1。每個節點到自己有一條長為0的路徑。一棵樹從根到葉子節點恰好存在一條路徑。

對於任意的節點ni,ni的深度為從根到ni的唯一路徑長。ni的高是從ni到一片葉子的最長路徑的長。因此,所有的樹葉的高度都是0,一棵樹的高等於它的根節點的高。一棵樹的深度總是等於它最深葉子的深度;該深度等於這棵樹的高度。

 

樹的實現

實現樹的一種方法可以是在每一個節點除資料外還要有一些指標,使得該節點的每一個兒子都有一個指標指向它。但是由於每個節點的兒子樹可以變化很大而且事先不知道,故在各個節點建立子節點的連結是不可行的,這樣將會浪費大量的空間。

實際的做法很簡單:將每個節點的所有兒子都放在樹節點的連結串列中。下面是典型的宣告:

typedef struct TreeNode *PtrToNode
struct TreeNode{
  ElementType Element;
  PtrToNode FirstChild;
  PtrToNode NextSibling
}

下面是兒子兄弟表示法的圖示:

樹的遍歷及應用

一個常見的使用是作業系統中的目錄結構。unix中的目錄就是含有它的所有兒子的一個檔案,下面是一個列印目錄的例子,輸出的格式是:深度為di的檔案的名字將被di次跳格tab後縮排:

static void
ListDir(DictoryOrFile D, int Depth){
  if(D is a legitimate entry){
    PrintName(D, Depth);
  if(D is a directory)
    for each childm C, of D
      ListDir(C, Depth + 1);
  }
}
void ListDirectory(DirectoryOrFile D){   ListDie(D, 0); }

上述的遍歷策略叫做先序遍歷。在先序遍歷中,對節點的處理工作是在他的諸子節點被處理之前進行的。另一種遍歷樹的方法是後序遍歷。在後序遍歷中,每一個節點處理的工作是在他的諸子兒子節點計算之後進行的。

 

記錄一個目錄大小的例程

static void SizeDirectory(Directory D){
  int TotalSize=0;
  if(D is a legitimate entry){
    for each child, C of D:
      TotalSize +=SizeDirectory(C);
  }
  return TotalSize;
}

 

二叉樹

二叉樹是一種樹,他的每個節點都不能有多於兩個的兒子。二叉樹的一個性質是平均二叉樹的深度要比N小的多,分析表明平均的深度為O(sqrt(N)),而對於特殊的二叉樹而言,其深度的平均值是O(logN)的。

對於二叉樹的實現,最多有兩個兒子,我們可以用指標直接指向它們。在宣告中,一個節點就是由Key(關鍵字)資訊加上兩個指向其他節點的指標組成的結構。

typedef struct TreeNode *PtrToNode;
typedef struct PtrToNode Tree;
struct TreeNode{
  ElementType Element;
  Tree Left;
  Tree Right;
};

二叉樹上就是圖,在畫二叉樹的時候,我們一般不會畫出NULL指標,因為具有N個節點的每一棵二叉樹都將需要N+1個NULL指標。二叉樹有許多與搜尋無關的重要應用。二叉樹的重要用處之一是在編譯器的設計原則領域。

 

表示式樹

下面是一個表示式樹的例子:

表示式樹的樹葉是運算元,比如常數或者變數,而其他的節點為操作符。由於這裡所有操作都是二元的,因此這棵特定的樹正好是二叉樹。有的節點也有可能只有一個兒子,如具有一目的減運算子的情形。在上面的樹中,左子樹的值是a+(b*c),右子樹的值是((d*e)+f)*g,整棵樹的表示(a+(b*c))+(((d*e)+f)*g)。

對於上面的二叉樹,我們可以通過遞迴產生一個帶括號的左表示式,然後打印出在根處的運算子,最後在遞迴的產生一個帶括號的右表示式進而得到一箇中綴表示式。這樣一般的方法稱為中綴表示式,由於其產生的表示式型別,這種遍歷很容易記住。

我們也可以通過後序遍歷的方式,得到表示式的字尾表示式。

 

構造一顆表示式樹

下面我們給出一種演算法,來把表示式的字尾表示轉化為表示式樹。對於將中綴表示式轉換為字尾表示式的演算法,我們可以通過棧進行實現。對於構建表示式樹的演算法:我們一次一個符號的讀入表示式,如果符號是運算元,那麼我們就建立一個單節點數並將一個指向它的指標推入棧,如果符號是操作符,那麼我們就從棧中彈出指向兩棵樹T1和T2的那兩個指標並形成一顆新的數,該樹的根就是操作符,它的左,右兒子分別指向T2和T1。然後將指向這棵樹的指標壓入棧中。

 

查詢樹ADT——二叉查詢樹

二叉樹的一個重要的應用就是查詢。假設樹中的每個節點被指定一個關鍵字值。在我們的例子中,雖然任意複雜的關鍵字都是可以的,但是為了簡單起見,假設它們都是整數。我們還將假設,所有字是互異的,後面再處理重複的情況。

使得二叉樹成為二叉查詢樹的性質是:對於樹中的每個節點X,它的左子樹中所有關鍵字值都小於X的關鍵字值,而它的右子樹中所有關鍵字值大於X的關鍵字值。

二叉查詢樹的平均深度是O(logN)。

 

二叉查詢樹的宣告和MakeEmpty

struct TreeNode
typedef struct TreeNode *Position;
typedef struct TreeNode *SearchTree;

struct TreeNode{
  ElementType Element;
  SearchTree Left;
  SearchTree Right;
};

SearchTree
MakeEmpty(SearchTree T){
  if(T != NULL){
    MakeEmpty(T->Left);
    MakeEmpty(T->Right);
   free(T);
  }
  return NULL:
}

 

Find

find操作一般是需要返回具有關鍵位元組點的指標,如果節點不存在則返回NULL。如果T為NULL,那麼我們就返回NULL。否則,如果儲存在T中的關鍵字是X,則返回T。否則,我們遞迴的呼叫遍歷左子樹或者右子樹,這取決於當前節點和X之間的關係。

下面的程式碼是通過遞迴進行實現的,我們發現函式中的兩次遞迴都是尾遞迴,很明顯可以通過goto進行實現。但是在這裡進行尾遞迴也是合理的,降低速度換的程式碼的簡明性,並且使用得棧空間也是O(logN)。

Position
Find(ElementType X, SearchTree T){
  if(T == NULL)
    return NULL;
  if(X < T->Element){
    Find(X, T->Left);
  }else if(X > T->Element){
    Find(X, T->Right);
  }else{
    return T;
  }
}

 

相關推薦

常見基本資料結構——查詢AVL

常見資料結構——樹 處理大量的資料時,連結串列的線性時間太慢了,不宜使用。在樹的資料結構中,其大部分的執行時間平均為O(logN)。並且通過對樹結構的修改,我們能夠保證它的最壞情形下上述的時間界。 樹的定義有很多種方式。定義樹的自然的方式是遞迴的方式。一棵樹是一些節點的集合,這個集合可

常見資料結構(棧、佇列、陣列、連結串列和紅黑

(一)棧 棧:stack,又稱堆疊,它是運算受限的線性表,其限制是僅允許在標的一端進行插入和刪除操作,不允許在其 他任何位置進行新增、查詢、刪除等操作。 簡單的說:採用該結構的集合,對元素的存取有如下的特點先進後出(即,存進去的元素,要在後它後面的元素依次取出後,才能取出該元素)。例如,子彈

C語言基本資料結構的三種遍歷節點數以及深度演算法)

關於二叉樹的定義,網上有比較好的介紹,在這裡就簡單介紹二叉樹的一些性質 二叉樹的基本性質 1)二叉樹的第i層上至多有 2^(i-1)(i ≥1)個結點; 2)深度為 h 的二叉樹中至多含有 2^h – 1 個結點; 3)若在任意一棵二叉樹中,有 n0 個葉子結點,有 n2

基本資料結構——的建立遍歷求葉子節點深度計算

/* 新建立一棵二叉樹,遍歷,查詢樹的高度,查詢樹的葉子節點,和總結點數  然後再計算距離最遠的兩個節點。 SQ 2014-04-20 */ #include<stdio.h> struct Node{     int data;     struct Node

【圖解資料結構】 一組動畫徹底理解三種遍歷

二叉樹的遍歷是指從根結點出發,按照某種次序依次訪問二叉樹中所有結點,使得每個結點被訪問一次且僅被訪問一次。 在二叉樹的遍歷中存在三種較為常用的遍歷方式:前序遍歷、中序遍歷、後序遍歷。接下來我將嘗試著用三組動畫向讀者詳細的介紹這三種遍歷方式的邏輯思路,希望讓讀者看到任何的二叉樹都能在腦海中快速的勾勒出動畫。

[PTA] 資料結構與演算法題目集 6-12 搜尋的操作集

唯一比較需要思考的刪除操作: 被刪除節點有三種情況: 1、葉節點,直接刪除 2、只有一個子節點,將子節點替換為該節點,刪除該節點。 3、有兩個子節點,從右分支中找到最小節點,將其值賦給被刪除節點的位置,接著刪除這個最小節點    // 函式Insert將X插入二叉搜尋樹BST並返

資料結構的Java實現(十)——

目錄 樹 二叉樹 樹 樹(tree)是一種抽象資料型別(ADT),用來模擬具有樹狀結構性質的資料集合。它是由n(n>=0)個有限節點組成一個具有層次關係的集合。節點一般代表一些實體,在java中節點一般代表物件。連線節點的線稱為邊,一般從一個節點到另一個節點的唯

Java資料結構:中根次序遍歷排序

        昨天離開了創新創業基地,有點難受,雖然換來了高效,但是總覺的難受,一起度過了半年,昨天離開了。 說正事,今天更新二叉排序樹的中根遍歷。         思想:其實沒啥,類似與二叉樹的非遞迴中

基礎資料結構與演算法實現(2)—搜尋BST

import java.util.LinkedList; import java.util.Queue; public class BST <E extends Comparable<E>> { private c

資料結構與演算法(C語言) | 排序

二叉排序樹的定義—— 二叉排序樹 ( Binary Sort Tree) 或者為空;或者是具有如下特性的二叉樹: (1)若根的左子樹不空,則左子樹上所有結點的關鍵字均小於根結點的關鍵字; (2)若

資料結構-從底向上層次遍歷

【題目來自灰灰考研】 二叉樹採用二叉連結串列進行儲存(如下所示),每個結點包含資料域Data,左孩子指標域left和右孩子指標域right。請設計演算法給定一顆樹,返回其節點值從底向上的層次序遍歷(按從葉節點所在層到根節點所在的層遍歷,然後逐層從左往右遍歷)。 Typed

資料結構資料結構C語言的實現(簡單

簡單二叉樹 /* * 二叉樹 */ #include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FAL

演算法與資料結構(3):基本資料結構——連結串列佇列有根

原本今天是想要介紹堆排序的。雖然堆排序需要用到樹,但基本上也就只需要用一用樹的概念,而且還只需要完全二叉樹,實際的實現也是用陣列的,所以原本想先把主要的排序演算法講完,只簡單的說一下樹的概念。但在寫的過程中才發現,雖然是隻用了一下樹的概念,但要是樹的概念沒講明白的話,其實不太好理解。所以決定先介紹一下基本的資

一本正經的聊資料結構(6):最優 —— 哈夫曼

![](https://cdn.geekdigging.com/DataStructure/head.png) 前文傳送門: [「一本正經的聊資料結構(1):時間複雜度」](https://www.geekdigging.com/2020/03/28/6072951828/) [「一本正經的聊資料結構(

那些年面試中常見資料結構基礎和演算法題(下)

前言 這是 資料結構和演算法面試題系列的下半部分,這部分主要是演算法類 包括二分查詢、排序演算法、遞迴演算法、隨機演算法、揹包問題、數字問題等演算法相關內容。本系列完整程式碼在 github 建了個倉庫,所有程式碼都重新整理和做了一些基本的測試,程式碼倉庫地址在這裡: shishujuan/dsalg

Python學習筆記 - 基本資料結構:元組列表字典集合

序列 序列是具有先後關係的一組元素 序列是一維元素向量,元素型別可以不同 序列是一個基類型別,字串、元組、列表都屬於序列。 序列處理函式及方法主要有: # 判斷某一元素x是否在序列s中 x in s x not in s # 連線兩個序列 s + t # 將序列s複製n

java基礎():談談Java基本資料結構

資料結構是計算機儲存,組織資料的方式。資料結構是指相互之間存在一種或多種特定關係的資料元素的集合。通常情況下,精心選擇的資料結構可以帶來更高的執行或儲存效率。資料結構往往同高效的檢索演算法和索引技術有關 java中常見的幾種資料結構(也是初級工程師常見面試題)主要是一些常見的容器,它們主要來自於Collec

linux裝置驅動中重要的3個數據結構 &&Linux裝置驅動模型幾個基本資料結構模型:kobjectksetsubsystem

大多數基本的驅動操作涉及到核心的3個重要資料結構:file_operations,file 和inode。 我們已經擁有一些裝置號,但是如何將其與驅動操作連在一起呢?file_operations結構就是這個橋樑,這個結構體定義在<Linux/fs.h>中,它是

基本資料結構、圖

一、二叉樹 以下采用連結串列結構來實現上圖的二叉樹: #include <cstdlib> #include <iostream> using namespace std; struct mNode { int

常見基本資料結構——表

表 ADT 形如A1,A2,A3,.....,An這樣的表。這個表的大小是n,大小為0的表為空表。 對於除空表外的任何表,我們說A[i+1]後繼A[i]並且A[i-1]前驅A[i]。表中的第一個元素A[1]不定義前驅,最後一個元素A[N]不定義後繼。 表ADT上面的操作:PrintList,MakeEmpty