ツリー、ツリートラバーサルとヒープソート

ツリーベース

定義1つのツリー

方法の1つの二つの定義

ツリー:非線形構造

1つのツリーが集合N(N> = 0)の要素であり
、N = 0、と呼ばれるヌルツリー
ツリーが参照先行要素、根、木のルートせず、特定のノードであり
、加えて、ツリーのルート唯一の前駆体の残りの要素は、ゼロまたはそれ以上のフォローアップ、無ルート前身のみ後継者が存在することができます


2再帰的定義
ツリーTは、要素の集合N(0、N> =)であり、 n = 0で、空のツリーが呼び出され
、その唯一一つの特定の要素及び根を、残りの要素は、m個のばらばらに分割することができますコレクション、T1、T2、T3 ...のTm 、 および各セットはまた、ルートと、それ自身のサブツリーを有する部分木Tの部分木として知られる木であります

用語クラスタ番号2

前駆体:先に現在のノードの要素
洪水の後:現在の後のノード要素
ノード:ツリー内のデータ要素
ノード次数のは:ノード数は、表記D(V)と呼ばれる程度のサブツリーがある
ノード:リーフ・ノードを0度の点であり、終端ノード、リーフノードと呼ばれる、エンドノード
ブランチノード:ノードの次数が0でない、非終端ノードがブランチノードまたは呼ばれ
、ノード間の関係:分岐連結
中間残し、末尾にルートノード以外のブランチ、リーフノードもちろん除く、ピンチヘッド内部ノード
ツリーのを:ツリー度が各ノードの最大値です。


子供(息子の子)ノード:ノードの子と呼ばれる部分木のノードのルート
各サブツリーの親のルートであるノード:親(親親)ノード。
兄弟(兄弟)ノード:ノードが同じ親ノードを有する
祖先ノード:分岐上のすべてのノードにルートノードからノードれる
ような子孫:すべてのサブツリーノードはノードと呼ばれ子孫である
レベルのノード:最初の層のルート・ノードは、第2層は、ルートノードの子である、というように、Lとして指定(V)
ツリーの深さ(高さ深さ):ツリーの最高レベル
いとこ:同じ層内の親ノード。

順序木:サブツリーノードは、交換することができない(順序付きサイズ兄弟)順序付けされ
順序付けられていない木を:サブツリーノードは順不同であり、交換することができます


パス:Kツリーノードn1、... NK N2は、niは親のN(I + 1)で満たし、経路がN1と呼ばれる、NK、それは以前の後にラインの下の文字列であります親(前駆体)ノード

経路長=長さ - 1つのパス内のノード、及び分岐の数

森:互いに素ツリーM(M> = 0)ツリー
ノードのために、森林であるサブツリーのセット、

3つのツリー機能:

ユニークなルート
サブツリー互いに素な
ルートを除く3は、各要素がゼロ以上の後続有することができ、唯一の前駆体を有することができ、
4ルート親ノード(前駆体)を有していないが、何のリーフノードの子ノードが存在しない(後継)
5 VJ VIは親、次にL(VI)= L(VJである )-1、 つまり子ノード1の親のレベル未満であります

2進コンセプト

1つの特長

各ノード1まで2サブツリー
度より大きい2不在のバイナリノード
順序木である2、左サブツリー、右サブツリーが順序で、交換することができないため
、特定のノードが唯一のサブツリーであっても3、私たちは、それが左または右のサブツリーサブツリーされているかどうかを決定する必要があります

5つのパターン2進木

空1バイナリ
2は、1つのルートノードである
だけ左サブツリーのルートノード3
4のみルートの右サブツリー
5及び左サブツリーの右の部分木を持つルートノード

3斜めツリー

ツリー、ツリートラバーサルとヒープソート

左斜めの木は:すべてのノードがサブツリーのみ残っている
右斜めツリーを:すべてのノードが唯一の右部分木を持っています

4完全なバイナリツリー

ツリー、ツリートラバーサルとヒープソート

バイナリツリーのノードのすべての分岐は、左右のサブツリーのサブツリー、およびすべてのリーフノードは、底部層に存在しているが。
バイナリ同じ深さは、完全なバイナリツリーのノードまでの
k個の深さ(1 <= K <= N )、 ノードの合計数は2 **(K)-1であります

5 完全二叉树

ツリー、ツリートラバーサルとヒープソート

二分木の深さがKである場合、K-1層のノードからバイナリツリー内の層の数が最大数をヒットし、k番目の層内のすべてのノードは、完全二分木である左側に集中している
完全なバイナリツリーがいっぱいによってバイナリリード
完全なバイナリツリーは完全二分木である必要があり、必ずしも必要ではないが、完全なバイナリツリーは完全なバイナリツリーである
k個の深さ(1 <= K <= N )、 ノードの最大数は2である** K-1、場合最大時間それは完全なバイナリツリーです

財産3分木

バイナリツリーにおけるi番目の層の上に1は、最大2 ** I-1のノードを有し、(I> = 1)

深さkの2分木、高々2 ** K -1ノード(K> = 1)

そのエンド・ノードがN0であればいずれかの二分木T 3は、次数2のノードがN2であり、1 + N 2 = N 0が-1ノードと次数2のリーフノードの数を=。

证明:
总结点数为n=n0+n1+n2,其中n0为度数为0的节点,及叶子节点的数量,n1为度数为1 的节点的数量,n2为节点为2度数的数量。
一棵树的分支数为n-1,因为除了根节点外,其余结点都有一个分支,及n0+n1+n2-1
分支数还等于n0*0+n1*1+n2*2及 n1+2n2=n-1
可知 2*n2+n1=n0+n1+n2-1 及就是 n2=n0-1


4 高度为k的二叉树,至少有k个节点
5 具有n个节点的完全二叉树的深度为int(log2n)+1 或者 math.ceil(log2(n+1))

6 有一个n个节点的完全二叉树, 结点按照层序编号,如图

ツリー、ツリートラバーサルとヒープソート

如果i=1,则节点i是二叉树的根,无双亲,如果i>1,则其双亲为int(i/2),向下取整。就是叶子节点的编号整除2得到的就是父节点的编号,如果父节点是i,则左孩子是2i,若有右孩子,则右孩子是2i+1,。
如果2i>n,则结点i无左孩子,及结点为叶子结点,否则其左孩子节点存在编号为2i。

如果2i+1>n,则节点i无右孩子,此处未说明是否不存在左孩子,否则右孩子的节点存在编号为2i+1。

二 二叉树遍历

1 遍历方式

遍历: 及对树中的元素不重复的访问一遍,又称为扫描

1 广度优先遍历

一次将一层全部拿完,层序遍历

ツリー、ツリートラバーサルとヒープソート
及 1 2 3 4 5一层一层的从左向右拿取

2 深度优先遍历

设树的根结点为D,左子树为L,右子树为R。且要求L一定要在R之前,则有下面几种遍历方式

1 前序遍历,也叫先序遍历,也叫先跟遍历,DLR
ツリー、ツリートラバーサルとヒープソート
1-2-4-5-3-6
2 中序遍历,也叫中跟遍历, LDR
ツリー、ツリートラバーサルとヒープソート
4-2-5-1-6-3
3 后序遍历,也叫后跟遍历,LRD
ツリー、ツリートラバーサルとヒープソート
4-5-2-6-3-1

三 堆排序

1 堆定义

1 堆heap 是一个完全二叉树
2 每个非叶子结点都要大于或等于其左右孩子结点的值称为大顶堆

ツリー、ツリートラバーサルとヒープソート

3 每个非叶子结点都要小于或者等于其左右孩子结点的值称为小顶堆

ツリー、ツリートラバーサルとヒープソート

4 根节点一定是大顶堆的最大值,小顶堆中的最小值

2 堆排序

1 构建完全二叉树

1 待排序数字为 49 38 65 97 76 13 27 49

2 构建一个完全二叉树存放数据,并根据性质5对元素进行编号,放入顺序的数据结构中

ツリー、ツリートラバーサルとヒープソート

3 构造一个列表为 [0,49,38,65,97,76,13,27,49]的列表

2 构建大顶堆

1 度数为2的结点,如果他的左右孩子最大值比它大,则将这个值和该节点交换
2 度数为1 的结点,如果它的左孩子的值大于它,则交换
3 如果节点被置换到新的位置,则还需要和其孩子节点重复上述过程

3 构建大顶堆--起点选择

ツリー、ツリートラバーサルとヒープソート

1 从完全二叉树的最后一个结点的双亲开始,及最后一层的最右边的叶子结点的父结点开始
2 结点数为n,则起始节点的编号为n//2(及最后一个结点的父节点)

4 构建大顶堆--下一个节点的选择

从起始节点开始向左寻找其同层节点,到头后再从上一层的最右边节点开始继续向左逐步查找,直到根节点

ツリー、ツリートラバーサルとヒープソート

5 大顶堆目标

确保每个结点的都比其左右结点的值大

ツリー、ツリートラバーサルとヒープソート
第一步,调换97和38,保证跟大

ツリー、ツリートラバーサルとヒープソート
第二步,调换49和97

ツリー、ツリートラバーサルとヒープソート
第三步,调换76和49

ツリー、ツリートラバーサルとヒープソート
第四步,调换38和49

此时大顶堆的构建已经完成

3 排序

将大顶堆根节点这个最大值和最后一个叶子节点进行交换,则最后一个叶子节点成为了最大值,将这个叶子节点排除在待排序节点之外,并从根节点开始,重新调整为大顶堆,重复上述步骤。

ツリー、ツリートラバーサルとヒープソート
ツリー、ツリートラバーサルとヒープソート
ツリー、ツリートラバーサルとヒープソート
ツリー、ツリートラバーサルとヒープソート
ツリー、ツリートラバーサルとヒープソート
ツリー、ツリートラバーサルとヒープソート
ツリー、ツリートラバーサルとヒープソート

四 实战和代码

1 打印树

l1=[1,2,3,4,5,6,7,8,9]
打印结果应当如下

ツリー、ツリートラバーサルとヒープソート

思路:可通过将其数字映射到下方的一条线上的方式进行处理及就是 8 4 9 2 0 5 0 1 0 6 0 3 0 7 0 的数字,其之间的空格可以设置为一个空格的长度,其数字的长度也可设置为固定的2,则

ツリー、ツリートラバーサルとヒープソート

则第一层第一个数字据前面的空格个数为7个,据后面的空格也是7个,
第二层第一个数字据前面的空格个数为3个,第二个数字距离后面的空格也是3个,
第三层据前面的空格为1,第三层最后一个据后面的空格也是1,
第四层据前面的空格是0,第四层最后一个据后面的空格也是0,
现在在其标号前面从1开始,则层数和空格之间的关系是

1 7
2 3
3 1
4 0
转换得到
4 7
3 3
2 1
1 0

及就是 2**(l-1) -1 l 表示层数
间隔关系如下
1 0
2 8
3 4
4 2
转换得到
4 0
3 8
2 4
1 2
及就是 2**l其中l 表示层数。

代码如下

import  math 
# 打印二叉树
def  t(list):
    '''
    层数      层数取反(depth+1-i,depth表示总层数,此处为4,i表示层数)   据前面的空格数            间隔数        每层字数为
    1            4                                                              7                     0              1
    2            3                                                              3                     7              2
    3            2                                                              1                     3              4
    4            1                                                              0                     1              8
                                                                    (2**(depth-i)-1)      (2**(depth-i)-1)        (2**i)   

    层数和数据长度的关系是 n表示的是数据长度
    1     1  
    2-3   2   
    4-7   3
    8-15  4       
    2**(i-1)<num<(2**i)-1,及就是int(log2n) +1 及 math.ceil(log2n)
    '''
    index=1
    depth=math.ceil(math.log(len(list),2))    #此处获取到的是此列表转换成二叉树的深度,此处前面插入了一个元素,保证列表和二叉树一样,其真实数据都是从1开始
    sep='  ' # 此处表示数字的宽度 
    for  i in range(depth):
        offset=2**i #每层的数字数量1  2  4  8  
        print (sep*(2**(depth-i-1)-1),end="")  # 此处取的是前面空格的长度
        line=list[index:index+offset] #提取每层的数量
        for  j,x  in enumerate(line):
            print ("{:>{}}".format(x,len(sep)),end="") # 此处通过format来获取其偏移情况,第一个x表示其大括号中的内容,第二个表示偏移的程度
            interval= 0  if  i ==0  else  2**(depth-i)-1  # 此处获取到的是间隔数,当值大于1时,满足如此表达式
            if  j < len(line)-1: #选择最后一个时不打印最后一个的后面的空格,及就是1,3,7后面的空格
                print (sep*interval,end="")
        index += offset
        print ()

结果如下
ツリー、ツリートラバーサルとヒープソート

2 堆排序算法实现

# 构建一个子树的大顶堆
def  heap_adjust(n,i,array):
    '''
    调整当前结点(核心算法)
    调整的结点的起点在n//2(二叉树性质5结论),保证所有调整的结点都有孩子结点
    :param  n : 待比较数个数
    :param  i : 当前结点下标
    :param array : 待排序数据
    :return : None
    '''
    while  2*i<=n: # 孩子结点判断,2i为左孩子,2i+1为右孩子 
        lchile_index= 2*i  #选择结点起始并记录 n=2*i-1,因为其是从0开始,因此只有len()-1
        max_child_index=lchile_index  
        # 判断左右孩子的大小,并将大的赋值给max_child_index 
        if  n > lchile_index  and  array[lchile_index+1] > array[lchile_index]: #说明其有右孩子,且右孩子大于左孩子 
            max_child_index=lchile_index+1  #n=2i+1 # 此时赋值的是下标
        # 判断左右孩子的最大值和父结点比较,若左右结点的最大值大,则进行交换
        if  array[max_child_index] > array[i]:  #此处的i是父节点,通过和父节点进行比较来确认其最大,
            array[i],array[max_child_index]=array[max_child_index],array[i]
            i= max_child_index   #右子节点的下标会赋值到父结点,并将其值赋值到父结点,
        else:
            break 
# 构建所有的大顶堆传入参数
def  max_heap(total,array):
    for i in range(total//2,0,-1):  #构建最后一个叶子结点的父结点
        heap_adjust(total,i,array)  #传入总长和最后一个叶子结点的父结点和数列
        print  (t(array))
    return  array
#构建大顶堆,起点选择    
def  sort(total,array):    # 此处起点是1,因此必须在前面添加一个元素,以保证其位置编号和树相同
    while  total>1:
        max_heap(total,array)
        array[1],array[total]=array[total],array[1]  #将最后一个结点和第一个结点调换,
        total-=1
    return array

结果如下
ツリー、ツリートラバーサルとヒープソート

3 总结

ヒープはソートヒープはソート最大値または最小値スタックの上部で選択、選択したスタック自然とソート
時間複雑
時間複雑ヒープの並べ替えは、元の記録スタックの状態ので、O(nlog2 n)で並べ替えません敏感、従ってそれがあるO(nlog2 n)が最良と最悪平均時間複雑であるかどうかを

空間複雑
交換スペースを使用したこと以外は、空間複雑さはO(1)で
の安定性
不安定ソートアルゴリズム

おすすめ

転載: blog.51cto.com/11233559/2401524