ツリーベース
定義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)で
の安定性
不安定ソートアルゴリズム