Python&&数据结构
数据结构部分 一
单链表(线性表)
具有数据区与链接区(指针区) 链表与顺序都抽象为称为线性表
单链表的操作:
判断链表是否为空 is_empty()
链表长度 length()
遍历整个链表 travel()
链表头部添加元素 add(item)
链表尾部添加元素 append(item)
指定位置添加元素 insert(pos,item)
删除节点 remove(item)
查找结点是否存在 search(item)
Python中变量表示的本质
a = 10 # python中a!=10,a不是10的别名,为10存储的地址 a【】-->【10】
b = 20
Python交换数 a,b = b,a
声明变量 a = 10
找到空间存储10 --> 找一个空间,存放a以及10的地址 (这玩样相当于指针) 变量即指针!!!
Python变量中保存的不是值是地址
使用变量时为取变量所指地址的值
节点的实现 链表使节点可操作
分析不同节点
class Node(object):
'''节点'''
def __init__(self,item,next):
self.elem = item # 保存数据
self.next = None # 可指向下一节点1
'''Python中也可以用列表元组的数据结构表示'''
class Single_link_list(object):
'''单链表'''
def __init__(self,node = None):
self.__head = node
def is_empty(self):
return self.__head == None #返回 Turn or False
def length(self): #返回节点的个数 通过游标(指针)记录当前的访问位置的结点 cur 用来移动遍历节点
cur = self.__head
count = 0 #记录数量
while cur != None :
count += 1 #cur移动一位后count+1
cur = cur.next #cur == None时退出循环
return count
def travel(self):
cur = self.__head
while cur != None :
print(cur.elem,end = ' ')
cur == cur.next
print('')
def add(self,item):
'''头插法'''
node = Node(item)
node.next = self.__head
self.__head = node
def append(self,item):
'''尾插法'''
node = Node(item)
if self.is_empty() :
self.__head = node
else :
cur = self.__head
while cur.next != None :
cur = cur.next
cur.next = node
def insert(self,pos,item):
'''
:param pos 从0开始索引
'''
if pos < 0 :
self.add(item)
elif pos >= self.length() : #pos > self.length()-1 最多索引到self.length()-1
self.append(item)
else :
node = Node(item)
pre = self.__head #前一位置操作
count = 0
while count < pos - 1 :
count += 1
pre = pre.next
'''循环推出之时pre指向pos-1'''
node.next = pre.next
pre.next = node
def remove(self,item):
pre = None
cur = self.__head
while cur != None :
if cur.elem == item :
if pre == None : #判断是否为头节点 pre cur 未移动
self.__head = cur.next
else :
pre.next = cur.next #pre = pre.next.next
return Ture
else :
pre = cur
cur = cur.next
return False
def search(self,item):
cur = self.__head
while cur != None :
if cur.elem == item :
return Ture
else :
cur = cur.next
return False
- 后继节点 --> 一个节点的下一节点
链表 与 顺序表
链表与顺序都抽象为称为线性表
- 链表 物理存储不连续
- 顺序表 物理存储连续
链表 | 操作 | 顺序表 |
---|---|---|
O(n) | 访问元素 | O(1) |
O(1) | 在头部插入/删除 | O(n) |
O(n) | 在尾部插入/删除 | O(1) |
O(n)遍历 | 在中间插入/删除 | O(n)数据搬迁 |
链表只记录了头节 要寻找其他节点必须要循环 可以分散存储 更好利用内存
顺序表都记录了 顺序表内存必须连续
单向循环链表
在单链表的基础上变形 使尾节点的指针指向头节点
class Node(object):
'''节点'''
def __init__(self,item,next):
self.elem = item # 保存数据
self.next = None # 可指向下一节点1
'''Python中也可以用列表元组的数据结构表示'''
class Single_Cycle_Link_List(object):
'''单向循环链表'''
def __init__(self,node = None):
self.__head = node
if node != None :
node.next = node
def is_empty(self):
return self.__head == None #返回 Turn or False
def length(self): #返回节点的个数 通过游标(指针)记录当前的访问位置的结点 cur 用来移动遍历节点
if self.is_empty() :
return 0
else :
cur = self.__head
count = 1 #记录数量
while cur.next != self.__head :
count += 1 #cur移动一位后count+1
cur = cur.next #cur == None时退出循环
return count
def travel(self):
if self.is_empty() :
return None
else :
cur = self.__head
while cur.next != self.__head : #cur刚好指向尾节点
print(cur.elem,end = ' ')
cur == cur.next
print(cur.elem)
def add(self,item):
'''先找尾节点后插 头插法'''
node = Node(item)
if self.is_empty() :
self.__head = node
node.next = node
else :
cur = self.__head
while cur.next != self.__head :
cur = cur.next
'''退出循坏cur指向尾节点'''
node.next = self.head
self.head = node
cur.next = node
def in_add(self,item):
'''先插后找尾节点 头插法'''
node = Node(item)
node.next = self.__head
self.__head = node
cur = self.__head
while cur.next != node.next :
cur = cur.next
cur.next = node
def append(self,item):
'''尾插法'''
node = Node(item)
if self.is_empty() :
self.__head = node
node.next = node
else :
cur = self.__head
while cur.next != self.__haed :
cur = cur.next
node.next = cur.next
cur.next = node
# nobe.next = self.__head
def insert(self,pos,item):
'''
:param pos 从0开始索引
'''
if pos < 0 :
self.add(item)
elif pos >= self.length() : #pos > self.length()-1 最多索引到self.length()-1
self.append(item)
else :
node = Node(item)
pre = self.__head #前一位置操作
count = 0
while count < pos - 1 :
count += 1
pre = pre.next
'''循环推出之时pre指向pos-1'''
node.next = pre.next
pre.next = node
def remove(self,item):
if self.is_empty() :
return False
pre = None
cur = self.__heade
while cur.next != self.__head : #cur指到尾节点处停止
if cur.elem == item :
if cur == self.__head : #判断是否为头节点(非仅一节点) pre cur 未移动 找尾节点
rear = self.__head #新游标指向1尾部
while rear.next != self.__head :
rear = rear.next
self.__head = cur.next
rear.next = self.__head
else : #中间节点
pre.next = cur.next #pre.next = pre.next.next
return Ture
else :
pre = cur
cur = cur.next
if cur.elem == item : #尾节点
if cur == self.__head :#莲仅有一个节点
self.__head = None
else :
pre.next = cur.next #相当于 pre.next = self.__head
return Ture
else :
return False
def search(self,item):
if self.is_empty() :
return False
else :
cur = self.__head
while cur != self.__head :
if cur.elem == item :
return Ture
else :
cur = cur.next
if cur.elem == item :
return Ture
else :
return False
分情况:
- 空链表
- 仅仅一个节点
- 有多个节点
- 头节点
- 尾节点
- 中间节点
return 返回值 函数结束
pass ?
break
continue
表头制作 表节点 与顺序表同 存储节点信息方便索引 理想 --> 特殊
双向链表(双面链表)
单项链表 所有链接区域都指向后继节点
节点改变 prev
-> next
- 后继节点
- 前驱节点
实现操作与单链表相同
import Single_Link_List
class Node(object):
'''节点'''
def __init__(self,item):
self.elem = item
self.next = None
self.prev = None
class Double_link_list(Single_Link_List): #继承
'''双链表'''
# def __init__(self,node = None):
# self.__head = node
# def is_empty(self):
# return self.__head is None #返回 Turn or False 判断是否是None 用is更好 == 也可
# def length(self): #返回节点的个数 通过游标(指针)记录当前的访问位置的结点 cur 用来移动遍历节点
# cur = self.__head
# count = 0 #记录数量
# while cur != None :
# count += 1 #cur移动一位后count+1
# cur = cur.next #cur == None时退出循环
# return count
# def travel(self):
# cur = self.__head
# while cur != None :
# print(cur.elem,end = ' ')
# cur == cur.next
# print('')
def add(self,item):
'''头插法'''
node = Node(item)
node.next = self.__head
# self.__head.prev = node
self.__head = node
node.next.prev = node
def append(self,item):
'''尾插法'''
node = Node(item)
if self.is_empty() :
self.__head = node
else :
cur = self.__head
while cur.next != None :
cur = cur.next
cur.next = node
node.prev = cur
def insert(self,pos,item):
'''
:param pos 从0开始索引
'''
if pos < 0 :
self.add(item)
elif pos > self.length()-1 : #pos > self.length()-1 最多索引到self.length()-1
self.append(item)
else :
node = Node(item)
cur = self.__head #前一位置操作
count = 0
while count < pos :
'''循环推出之时cur指向pos位置'''
count += 1
cur = cur.next
node.next = cur
node.prev = cur.prev
cur.prev = node #cur.prev.next = node
node.prev.next = node #cur.prev = node
""" while count < pos - 1 :
count += 1
pre = pre.next
'''循环推出之时pre指向pos-1'''
node.next = pre.next
pre.next = node
node.prev = pre
node.next.prev = node
""" #注意 node 的改变 比较
def remove(self,item):
cur = self.__head
while cur != None :
if cur.elem == item :
if cur == self.__head : #判断是否为头节点 pre cur 未移动
self.__head = cur.next
if cur.next : #判断链表是否只有一个叫节点
self.__head.prev = None
else :
pass
else :
cur.prev.next = cur.next
if cur.next :
cur.next.prev = cur.prev
esle :
pass
return Ture
else :
cur = cur.next
return False
def search(self,item):
cur = self.__head
while cur != None :
if cur.elem == item :
return Ture
else :
cur = cur.next
return False
栈(stack)
栈 一些地方称为堆栈,是一种容器,可以存入数据元素、访问元素、删除元素。只能在一端 push(输入) pop(输出)
栈数据结构只允许在一端进行操作,后进先出(LIFO,Last In First Out)的运作原理
栈(描述如何操作) 可以使用 顺序表和链表(解决了数据如何存放) 实现
栈的实现
使用顺序表(python中的列表)实现
栈的操作:
- stack() #创建
- push(item) #添加 压栈 入栈
- pop() #删除 弹出 栈顶元素
- peek() #取值(返回栈顶元素)
- is_empty() #判断是否为空
- size() #返回元素个数
# coding:utf-8
class Stack(object):
'''栈'''
def __init__(self): #创建
self.__list = []
def push(self,item): #添加 压栈 入栈
self.__list.append(item) "顺序表尾部添加时间复杂度 O(1)
"链表则从尾部添加,时间复杂度为O(1)
def pop(self): #删除 弹出 栈顶元素
return self.__list.pop()
def peek(self): #取值(返回栈顶元素)
if self.__list:
return self.__list[-1]
else:
return None
def dis_empty(self): #判断是否为空
return self.__list == []
# return self.__list 返回了列表 且不符合
# return not self.__list
def size(self): #返回元素个数
return len(self.__list)
队列
队列 只允许从一端进行插入操作(进入),另一端进行删除操作(取出) 一种先进先出(FIFO,First In First Out)的线性表 符合通常生活中的习惯
队列与双端队列的实现
队列的操作
- Queue() 创建
- enqueue(item) 添加 入队
- dequeue() 删除 出队
- is_empty() 判断
- size() 大小
class Queue(object):
def __init__(self):
self.__list = []
def enqueue(self,item):
self.__list.aqqend(item) #O(1)
# self.__list.insert(0,item) #O(n)
def dequeue(self):
return self.__list.pop(0) #O(1)
# return self.__list.pop() #O(n)
def is_empty(self):
return self.__list == None
# return not self.__list
def size():
return len(self.__list)
双端队列
两端都可以 添加、删除
相当于两个栈底部和在一起
操作
class Deque(object):
def __init__(self):
self.__list = []
def add_front(self,item):
self.__list.insert(0,item)
def add_rear(self,item):
self.__list.aqqend(item)
def remove_fornt():
return self.__list.pop(0)
def remove_rear():
return self.__list.pop()
def is_empty():
return self.__list == None
def size():
return len(self.__list)
简单算法
排序算法
本排序为默认从大到小 排序算法的稳定性 排序过程中 算法能否输出正确的结果 可能
冒泡排序
每过一遍 大的向后 小的向前 需要 n - 1 次冒泡
两个数相比较相邻 假设有一游标 比较游标当前的值至于其后面的值 将最大的值往后放
#Bubble sort
def bubble_sort(alist): #顺序表交换的是数值,链表交换的是节点
"冒泡排序
n = len(alist) #循环嵌套
for m in range(0,n-1): #每走一次找到一个较最大值 m 取值 0 ~ n-2
count = 0 #计数看是否已经有序
for i in range(0,n-1-m): #从头走到尾 从第零个到最后一个(n-1)的前面 由性质与后一数比较得到 每过一遍 需排序的最大的数到了最后 可以不再参与排序 则排序的两两比较的次数得以减小
if alist[i] > alist[i+1]:
alist[i],alist[i+1] = alist[i+1],alist[i]
count += 1 #发生一次交换着 计数+1 进行一次则说明本次未排序完成
if count == 0:
break
def bubble_sort_g(alist):
for i in range(len(alist)-1,0,-1): #每循环一次完成值减一 =0 退出不在循环 输出 i 取值 n-1 ~ 1
for j in range(i):
if alist[j] > alist[j+1]:
alist[j],alist[j+1] = alist[j+1],alist[j]
- 时间复杂度 最坏 O(n^2) 最好 O(n)
- 稳定性 稳定(升序、降序 都一样)
选择排序与插入排序
- 选择排序 在已有顺序的后面部分寻找一个最小的值 放在此部分最前面形成顺序
- 将最小的值找出来 放到前方(即与较最前的值交换) 最小 --> 次小
- 插入排序 相反
选择最小的放到比较的最前面 后从中取其它的部分值 再选最小的
def select_sort_me(alist): #若 第一个最小 就凉凉了
n = len(alist)
min = 0 #此处对 min 进行初始化 会不稳定
for i in range(n - 1):
for j in range(1 + i,n):
if alist[min] > alist[j]:
min = j
alist[i],alist[min] = alist[min],alist[i]
def select_sort(alist):
n = len(alist)
for j in range(n-1): # j: 0 ~ n-2
min_index = j
for i in range(j+1,n):
if alist[min_index] > alist[i]:
min_index = i #使退出后 min_index 为最小的下标
alist[j],alist[min_index] = alist[min_index],alist[j]
- 时间复杂度 最坏O(n^2) 最好O(n^2) 每次都要验证 最小
- 稳定性 按升序去选择 最大放到最后 取最大放后面 会出现不稳定情况 其不稳定
- (升序、降序 不同)相同数前后位置会变化
- 升序选择最大的放到后面
- 降序选择最小的放到前面
- (升序、降序 不同)相同数前后位置会变化
插入算法
将一个序列分别为有序与无序 将无序中第一个数的放入(插入)到有序中正确位置中去
//just my think
#include"stdio.h"
#define N 8
int main()
{
int arr[N] = {19,55,21,33,55,11,15};
int i,j,mo;
// for(i=0;i<=N-1;i++)
// scanf("%d",&arr[i]);
for(j=0;j<=N-2;j++)
for(i=j;i>=0;i--)//从下往上爬
{
if(arr[i+1]<arr[i])//判断当要插入的下一数(i+1处)<上有序的其中的数(在i处),使i+1插进去
{
{
mo=arr[i+1];//将存在[i+1]处地址的值给mo保护起来
arr[i+1]=arr[i];//实现插入将i处的数放到i+1处,上面的下移
arr[i]=mo;//两数成功对换
}
}
else
break;//也可以不跳出但废计算机资源
}
for(i=0;i<=N-1;i++)
printf("%3d",arr[i]);
return 0;
}
- 选择排序操作的是后面的 假定前面有序从后面无序序列中选择最小的放到前面去
- 插入排序操作的是前面的 假定前面有序,从后面无序序列中选数(第一个数),从右往左比较
# The learn not just I think
def insert_sort(alist):
n = len(alist)
# 从右边的无序序列中取出多少个元素执行这样的过程
for j in range(1,n)
i = j; # i = [1,……,n-1] i代表内层循环的起始值
# 执行从右边无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
while i > 0:
if alist[i] < alsit[i-1]:
alist[i],alist[i-1] = alist[i-1],alist[i]
i -= 1
else:
break
# i=j j-1 j-2 ... 1
# range(j,0,-1):
def insert_sort_other(alist):
for i in range(1,len(ailst)):
for j in range(i,0,-1):
if alist[j] < alist[j-1]:
alist[j],alist[j-1] = alist[j-1],alist[j]
insert_sort_other
时间复杂度 最坏O(n^2) 最优O(n^2)insert_sort
时间复杂度 最坏O(n^2) 最优O(n)- 稳定性 稳定(从后往前排)
希尔排序
希尔排序 是插入排序的一种 将一个无序序列分(按一定方式 间距)为多个无序序列(子序列) 进行判断 即比较的步长不在是插入排序的 1 而是可以按步长进行
- 经过第一次对子序列排序后 缩小间距 再重复进行 插入算法
- 以某一不长进行打断
'\n'
然后以每列为单位进行排序 - 通过循环使得所分成的子序列 同时进行操作(插入操作)
- 以某一不长进行打断
- 相当一 插入排序 中 1 ====> gap (步长)
def shell_sort():
n = len(alist)
gap = n // 2 # 步长
# i = gap # i += 1 # 对下一子序列进行操作
while gap >= 1 :# gap 最小步长是 1 故 gap 到 1 时执行最后一次
# 插入算法部分,与普通的插入算法的区别就是 gap 步长
for j in range(gap,n): # j = [gap,gap+1,gap+2,...,n-1]
'''处理所有子序列'''
i = j
while i > 0 : # 子序列进行循环 比较的插入算法
if alist[i] < alsit[i-gap]:
alist[i],alist[i-gap] = alist[i-gap],alist[i]
i -= gap
else:
break
# 缩短 gap 步长
gap //= 2
- 时间复杂度 最优: 根据步长定 最坏O(n^2)
- 稳定性:不稳定 相同数前后位置会变化
快速排序
建立某一值的高位与低位区 再某一元素所在的正确处(位置)进行分割 使用递归
- 寻找某一元素所在的位置 定义两个游标使得 low 游标前的比其小 high 游标后的比其大(通过交换实现) 最终使得 low 与 high 交会 然后从交汇处又从此将序列分为两部分 然后重复分割(再子序列上再次分割)
- 定义两个游标 进行夹击 对 high 与 low 游标同时判断
'''
if alist[h] < mid:
alist[l] = alist[h]
l += 1
elif alist[h] > mid:
h -= 1
else:
pass
if alist[l] < mid:
l -= 1
elif alist[l] > mid:
alist[h] = alist[l]
h -= 1
else:
pass
'''
# 递归嵌套的使用
# 动态 第一个元素下标与最后一个元素下标 寻找某一值的正确位置
def quick_sort(alist,first=0,last=len(alist)-1):
if first >= last:
return Ture
mid_value = alist[first]
low = first
high = last
while low < high:
# high 左移
while low < high and alist[high] >= alist[low]:
high -= 1
alist[low] = alist[high]
# low += 1
while low < high and alist[low] < alist[high]:
low += 1
alist[high] = alist[low]
# high -= 1
# 从循环退出时 low == high
alist[low] = mid_value
# 对 分割线(low == high) 左边的进行排序
quick_sort(alist,first,low-1)
# 再 low-1 可能小于 first 会出现 first < last 如 low == high == 0
# 如果算右边时子序列中 的左边 first 要变
# 对 分割线(low == high) 右边的进行排序
quick_sort(alist,low+1,last)
# quick_sort(alist[low+1:]) # 切片后返回一个新的列表
- 时间复杂度
- 最优(刚好可以对序列进行分割) O(n*log n) 表示n要被除以多少个2才达到1(n//2^x=1 ===> n=2^x ===> x=log2n)
- 最坏O(n^2)
- 稳定性:不稳定 相同(次序)数前后位置会变化
归并排序
对整个序列进行拆分 形成新的子序列(通过新列表进行合并) 直到只有一个元素 然后合并 小前大后
- python 中 如果列表
ls=[1,2,3]
进行ls[3:]
返回[]
- 递归 函数套娃 层层套 不可套才罢休 套方解
- 级级嵌套 级级返回
- 递归 函数套娃 层层套 不可套才罢休 套方解
def merge_sort(alist):
n = len(alist)
if n <= 1:
return alist
mid = n//2
# left 采用归并排序后形成有序的新列表
left_li = merge_sort(alist[:mid])
# right 采用归并排序后形成有序的新列表
right_li = merge_sort(alist[mid:])
# 将两个有序子序列合并为一个新整体
# merge(left,right)
left_pionter,right_pionter = 0,0
result = []
while left_pionter < len(left_li) and right_pionter < len(right_li):
if left_li[left_pionter] <= right_li[right_pionter]:
result.append(left_li[left_pionter])
left_pionter += 1
else:
result.append(right_li[right_pionter])
right_pionter += 1
result += left_li[left_pionter]
result += right_li[right_pionter]
return result
- 时间复杂度 (行分析 列分析) 直接
- 最优 O(n*log n) 表示n要被除以多少个2才达到1(n//2^x=1 ===> n=2^x ===> x=log2n)
- 最坏 O(n*log n)
- 稳定性:不稳定 相同数前后位置会不变化
- 空间上会有额外开销
其他排序算法
搜索
在一个项目集合中查找到特定一个项目的算法过程 返回值 Ture 或 False 表示其是否存在
搜索常见的方法:顺序查找、二分查找、二叉树查找、哈希查找
二分查找
分半查找 (折半查找)
- 处理已经排好序的(有序) 且支持下标索引
[]
(连续) - 关注起始与中间坐标 与中间值比较 然后分开 再次进行
- 递归 产生新序列
# 使用递归 函数调用产生新的 列表
def binary_search(alist,item):
n = len(alist)
mid = n//2
if n >0 :
if alist[mid] == item :
return Ture
elif item < alist[mid]:
return binary_search(alist[:mid],item) # 接受返回的结果
else :
return binary_search(alist[mid+1:],item)
return False
# 不使用递归 划分查找范围(与快速排序相思)
def binary_search_x(alist,item):
n = len(alist)
first = 0
last = n-1
mid = (first+last) // 2
while first <= last :
if alist[mid] == item :
return Ture
elif item < alist[mid]:
last = mid-1
else :
first = mid+1
return False
- 时间复杂度
- 最坏 O(log2n)
- 最优 O(1)
树
用来模拟具有树状结构性质的数据集合 一维空间 ===> 二维空间
- 节点 数据区 链接区 具有零个或多个链接区
- 每一个节点有零个或多个子节点
- 没有父节点的节点称为根节点
- 每一个非根节点有且只有一个父节点
- 除根节点外,每一个子节点可以分为多个不相交的子树
树的术语
- 节点的度:一个节点所含的子树的个数
- 树的度:树中最大节点的度
- 叶节点(终端节点):度为0的节点
- 父亲节点(父节点):一个含有子节点的节点,其为此子节点的父节点
- 孩子节点(子节点):有父节点的节点
- 兄弟节点:具有相同父节点的节点 互称为兄弟节点
- 节点的层次:一根节点为第一层,以此向下推
- 树的高度(深度):树中节点的最大层次
- 堂兄弟节点:父节点在同一层的节点互为堂兄弟节点
- 节点的祖先:从根到此节点所经历分支上的的所有节点
- 子孙:(与现实擦不多)以某节点为跟的子树中的任一节点都称为该节点的子孙
- 森林:有 m(m>=0) 课互不相交的树的合集称为森林
树的种类
- 无序树 树任意节点之间没有顺序关系
- 有序树 树任意节点之间具有顺序关系
- 二叉树 每一个节点最多含有两个子树
- 完全二叉树 除最后一层均达到最大连接数
- 满二叉树 全满
- 平衡二叉树(AVL树) 任意节点的子树的高度差不大于一
- 排序二叉树(二叉查找树) 与二分查找相似
- 完全二叉树 除最后一层均达到最大连接数
- 霍夫曼树
- B树
- 二叉树 每一个节点最多含有两个子树
树的存储与表示
顺序存储 将树存储在数组中
链式存储
树的应用
html xml MySQL数据库索引 文件系统目录 …………
二叉树
二叉树的概念
每个节点最多只有两个子树 左子树 右子树
二叉树的性质(特性)
性质1: 在二叉树的第I层上至多有2^(I-1)个结点(I>0)
性质2: 深度为k的二叉树至多有2^k - 1个结点(k>0)
性质3: 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;
**性质4:**具有n个结点的完全二叉树的深度必为 log2n+1
**性质5:**对完全二叉树,若从上至下、从左至右编号,则编号为I 的结点,其左孩子编号必为2I,其右孩子编号必为2I+1;其双亲的编号必为I/2(I=1 时为根,除外)
(1)完全二叉树——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
(2)满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
实现二叉树
实现节点
class Node(object):
def __init__(self,item):
self.item = item
self.lchild = None
self.lchild = None
class Tree(object):
def __init__(self):
self.root = None
# 完全二叉树方式添加 添加使用广度优先
def add(item):
node = Node(item)
if self.root is None:
self.root = node
return
queue = [self.root]
while queue:
cur_node = queue,pop(0)
if cur_node.lchild is None:
cur_node.lchild = node
return
else:
queue.append(cur_node.lchild)
if cur_node.rchild is None:
cur_node.rchild = node
return
else:
queue.append(cur_node.rchild)
遍历
广度优先遍历(层次遍历)
从 root 开始,从上到下 从左到右遍历整个树的节点 一层一层 横向(行)
一边 add 一边 取出 ===> 队列
class Node(object):
def __init__(self,item):
self.item = item
self.lchild = None
self.lchild = None
class Tree(object):
def __init__(self):
self.root = None
# 完全二叉树方式添加 添加使用广度优先
def add(item):
node = Node(item)
if self.root is None:
self.root = node
return
queue = [self.root]
while queue:
cur_node = queue,pop(0)
if cur_node.lchild is None:
cur_node.lchild = node
return
else:
queue.append(cur_node.lchild)
if cur_node.rchild is None:
cur_node.rchild = node
return
else:
queue.append(cur_node.rchild)
# 广度遍历
def Breadth_travel(self):
if self.root is None:
return False
queue = [self.root]
while queue:
cur_node = queue,pop(0)
print(cur_node.item,end=' ')
if cur_node.lchild is not None:
cur_node.lchild = node
if cur_node.rchild is not None:
cur_node.rchild = node
深度优先遍历
一层中:左 ==> 右 使用递归
先序遍历
-
根节点 ==> 左子树 ==> 右子树
-
def preorder(self,root): if root is None: return print(root.elem,end=' ') # 首先输出root self.preorder(node.lchild) # 处理左边的 self.preorder(node.rchild) # 处理右边的
中序遍历
-
左子树 ==> 根节点 ==> 右子树
-
def inorder(self,root): if root is None: return self.inorder(node.lchild) print(root.elem,end=' ') self.inorder(node.rchild)
后序遍历
-
左子树 ==> 右子树 ==> 根节点
-
def postorder(self,root): if root is None: return self.postorder(node.lchild) self.postorder(node.rchild) print(root.elem,end=' ')
二叉树有遍历确定树
有中序 + 另一其他序 同过 中序 + 根 将树的左右分开(找到左右子树) 另一其他序 性质找根