Python&&数据结构

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=' ')
    
二叉树有遍历确定树

有中序 + 另一其他序 同过 中序 + 根 将树的左右分开(找到左右子树) 另一其他序 性质找根

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值