python常见的数据类型与数据结构(二) 链表 单向链表 循环链表 双向循环链表 二叉树 二叉树的定义、层次遍历、先序、中序、后序遍历 N叉树 N叉树的定义和遍历
python常见的数据类型与数据结构(二) 链表 单向链表 循环链表 双向循环链表 二叉树 二叉树的定义、层次遍历、先序、中序、后序遍历 N叉树 N叉树的定义和遍历
- 链表
- 单向链表
- 循环链表
- 双向链表
- 二叉树
- 二叉树的定义
- 二叉树的层序遍历
- 二叉树的锯齿形层次遍历
- 二叉树的前序遍历
- 二叉树的后序遍历
- N叉树
- N叉树的定义
- N叉树的层序遍历
- N叉树的后序遍历
- 制作不易,感谢三连,谢谢啦
链表
- python和C语言一样没有专门构造链表的数据结构,但也一样使用其他方式来模仿链表。只不过C语言使用了结构体,python作为一门面向对象的语言使用类 (class)来完成相同的操作,并且更加清晰明白。ps我在一开始就不是很理解C语言的链表我当时以为LNode就是定义的名字,哈哈哈。
单向链表
- python中使用类来完成对象的实例化,并使用默认执行的__init__函数来完成初始化,单向链表顾名思义指向链表末尾,并且只能从前向后查找。
- 链表的每个检点包含至少两个元素其中next指向下一个节点的地址,val为当前节点的值,val可以有不止一个(不一定一定叫val,或next)
- val的值可以是任何数据类型,比如数字类型、字符串、列表和集合等,甚至可以是指向其他的链表,不过一般不会这么做,C语言的链表被人诟病的就是过于复杂难懂,python作为不那么在乎内存的语言也就不会选择把链表复杂化。
class ListNode(object): def __init__(self, x): self.val = x self.next = None head = ListNode(1) head.next = ListNode(1) head.next.next = ListNode(2) head.next.next.next = ListNode(3) head.next.next.next.next = ListNode(4)
循环链表
- 单向链表的一个缺点就是当我们循环到了末尾时就停止了,做不到继续,而循环链表则完美的解决了 这个问题,他的末尾节点next指向head开始节点,做到了循环。
end.next = head
双向链表
- 看似循环链表解决了单向链表的缺点,但是,如果要找到的值是末尾节点,我们就不得不遍历整个链表,而没有任何办法更快的找到所需要的节点,而这时双向链表就来解决问题了,他在循环链表的基础上添加了一个pre,next用来指向下一个节点,而怕热用来指向上一个节点,这样一来。双向链表的遍历时间复杂度最大也就是O(n/2)
class Node: def __init__(self, data=None): self.data = data self.next = None self.pre = None
二叉树
- 二叉树作为链表的变体,他的每个节点至多有两个子节点,也可以没有,二叉树在查找数据,在进行计算时有着天然的优势。
二叉树的定义
- 为了记忆方便,他的两个节点一般命名为left和right
class TreeNode(object): def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right root = TreeNode(1) root.left = TreeNode(2) root.right = TreeNode(3) root.left.left = TreeNode(4) root.left.right = TreeNode(5) root.right.left = TreeNode(6) root.right.right = TreeNode(7)
二叉树的层序遍历
- 二叉树的层序遍历(也称为广度优先遍历)是一种遍历二叉树的方法,其中我们首先访问根节点,然后访问所有子节点,接着访问孙子节点,以此类推。
def level_order_traversal(): if root is None: return [] queue = [root,0] queue_len = 2 result = [[]] while queue : if queue[0] != 0 : result[-1].append(queue[0].val) if queue[0].left : queue.append(queue[0].left) queue_len += 1 if queue[0].right : queue.append(queue[0].right) queue_len += 1 queue_len -= 1 queue.pop(0) elif queue[0] == 0 and queue_len > 1: result.append([]) queue_len -= 1 queue.pop(0) queue.append(0) queue_len += 1 else : return result print(level_order_traversal())
二叉树的锯齿形层次遍历
-
二叉树的锯齿形层次遍历(也称为之字形层序遍历)是二叉树层序遍历的一种变种。在这种遍历方式中,每一层的节点从左到右或从右到左交替出现。也就是说,第0层的节点从左到右,第1层的节点从右到左,第2层的节点又从左到右,以此类推。
(图片来源网络,侵删) -
为了实现这种遍历方式,我们可以在标准的层序遍历的基础上添加一些逻辑来判断当前层是否需要反转。具体来说,我们可以使用一个队列来保存待处理的节点,并在每一层处理完毕后,根据当前层的奇偶性来决定是否反转该层的节点顺序。
class Solution(object): def zigzagLevelOrder(self, root): """ :type root: TreeNode :rtype: List[List[int]] """ if root is None: return [] queue = [root] result = [] while queue : result.append([]) temp = [] for i in range(len(queue)) : if queue[i].left : temp.append(queue[i].left) if queue[i].right : temp.append(queue[i].right) result[-1].append(queue[i].val) queue = temp for i in range(1,len(result),2): result[i] = result[i][::-1] return result a = Solution().zigzagLevelOrder(root) print(a)
二叉树的前序遍历
- 二叉树的前序遍历是一种深度优先遍历方式,按照根节点-左子树-右子树的顺序访问二叉树的节点。这意味着在遍历二叉树的过程中,我们先访问当前节点,然后递归地访问左子树,最后访问右子树。
class Solution(object): def preorderTraversal(self, root): """ :type root: TreeNode :rtype: List[int] """ lis = [] if not root : return lis self.digui(root,lis) return lis def digui(self,root,lis): if root : lis.append(root.val) if root.left : self.digui(root.left,lis) if root.right : self.digui(root.right,lis) a = Solution().preorderTraversal(root) print(a)
二叉树的后序遍历
- 二叉树的后序遍历(Postorder Traversal)是一种树遍历算法,其中遍历的顺序是先遍历左子树,然后遍历右子树,最后访问根节点。这种遍历方式在很多应用中都很重要,比如计算表达式的值、删除节点等。
class Solution(object): def postorderTraversal(self, root): """ :type root: TreeNode :rtype: List[int] """ lis = [] if not root : return lis self.digui(root,lis) return lis def digui(self,root,lis): if root.left : self.digui(root.left,lis) if root.right : self.digui(root.right,lis) if root : lis.append(root.val) a = Solution().postorderTraversal(root) print(a)
N叉树
-
N叉树(N-ary Tree)是一种树形数据结构,其中每个节点可以有不多于N个子节点。与二叉树不同,N叉树的每个节点可以有任意数量的子节点,但不超过N个。二叉树是N叉树的一个特例,当N=2时,二叉树就是N叉树。
-
N叉树的遍历方式与二叉树类似,也可以采用前序遍历、中序遍历和后序遍历。然而,N叉树的中序遍历没有统一的定义,因为二叉树的中序遍历是基于其左子树、根节点和右子树的特定顺序,而N叉树没有明确的左右子树之分。
-
在N叉树的遍历中,前序遍历通常首先访问根节点,然后遍历每个子节点;后序遍历则首先遍历每个子节点,然后访问根节点。这两种遍历方式在N叉树中仍然适用。
-
N叉树在实际应用中具有广泛的用途。例如,B树(B-Tree)就是一种N叉树,用于维护排序数据的有序性,以便进行高效的插入、删除和搜索操作。B树的每个节点通常包含多个子节点,这些子节点按照特定的规则进行排序,以便在查找、插入和删除时保持树的平衡。
-
总之,N叉树是一种具有灵活性的数据结构,可以适应不同场景下的需求。通过调整N的值和节点的连接方式,可以实现各种复杂的树形结构。
N叉树的定义
- N叉树的节点通常包含一个数据元素和指向其子节点的指针数组。指针数组的大小取决于N的值,用于存储指向子节点的指针。如果某个节点没有N个子节点,那么指针数组的剩余部分可以设置为null或指向空节点。
class Node: def __init__(self, val=None, children=None): self.val = val self.children = children if children is not None else [] def add_child(self, node): self.children.append(node) # 创建N叉树 # 1 # /|\ # 2 3 4 # /|\ # 5 6 7 root = Node(1) child2 = Node(2) child3 = Node(3) child4 = Node(4) child5 = Node(5) child6 = Node(6) child7 = Node(7) child2.add_child(child5) child2.add_child(child6) child2.add_child(child7) root.add_child(child2) root.add_child(child3) root.add_child(child4)
N叉树的层序遍历
-
N叉树的层序遍历(Level Order Traversal)是一种按层次访问树中节点的遍历方式。类似于二叉树的层序遍历,我们从根节点开始,逐层访问树的节点,同一层的节点按照从左到右的顺序访问。
-
为了实现N叉树的层序遍历,我们可以使用队列(Queue)这一数据结构。首先将根节点入队,然后进入一个循环,在循环中不断从队列中取出节点,并访问其值。接着,将该节点的所有子节点(如果有的话)按照从左到右的顺序入队。循环继续直到队列为空,即所有节点都被访问过。
-
这里我使用列表来代替队列,只是本人习惯,不过python在对于队列的使用确实比较少。
def print_tree(node, level=0): if not node : return [] a = [] queue = [node] while len(queue): temp = [] temp1 =[] for i in queue : temp.append(i.val) for j in i.children: temp1.append(j) queue = temp1[:] a.append(temp[:]) print(a)
N叉树的后序遍历
- 后序遍历是一种深度优先遍历方法,对于二叉树来说,它的遍历顺序是左子树、右子树、根节点。然而,对于N叉树(每个节点可以有任意数量的子节点),后序遍历的定义可能有所不同,因为它没有一个固定的子节点顺序。但通常,后序遍历的定义是:先遍历所有子节点,然后再遍历根节点。
class Solution(object): def postorder(self, root): """ :type root: Node :rtype: List[int] """ result = [] if not root : return result self.digui(root,result) return result def digui(self,root,result) : for i in root.children : self.digui(i,result) result.append(root.val) a = Solution().postorder(root) print(a)
制作不易,感谢三连,谢谢啦
- 后序遍历是一种深度优先遍历方法,对于二叉树来说,它的遍历顺序是左子树、右子树、根节点。然而,对于N叉树(每个节点可以有任意数量的子节点),后序遍历的定义可能有所不同,因为它没有一个固定的子节点顺序。但通常,后序遍历的定义是:先遍历所有子节点,然后再遍历根节点。
-
- N叉树的节点通常包含一个数据元素和指向其子节点的指针数组。指针数组的大小取决于N的值,用于存储指向子节点的指针。如果某个节点没有N个子节点,那么指针数组的剩余部分可以设置为null或指向空节点。
-
- 二叉树的后序遍历(Postorder Traversal)是一种树遍历算法,其中遍历的顺序是先遍历左子树,然后遍历右子树,最后访问根节点。这种遍历方式在很多应用中都很重要,比如计算表达式的值、删除节点等。
- 二叉树的前序遍历是一种深度优先遍历方式,按照根节点-左子树-右子树的顺序访问二叉树的节点。这意味着在遍历二叉树的过程中,我们先访问当前节点,然后递归地访问左子树,最后访问右子树。
-
- 二叉树的层序遍历(也称为广度优先遍历)是一种遍历二叉树的方法,其中我们首先访问根节点,然后访问所有子节点,接着访问孙子节点,以此类推。
- 为了记忆方便,他的两个节点一般命名为left和right
- 二叉树作为链表的变体,他的每个节点至多有两个子节点,也可以没有,二叉树在查找数据,在进行计算时有着天然的优势。
- 看似循环链表解决了单向链表的缺点,但是,如果要找到的值是末尾节点,我们就不得不遍历整个链表,而没有任何办法更快的找到所需要的节点,而这时双向链表就来解决问题了,他在循环链表的基础上添加了一个pre,next用来指向下一个节点,而怕热用来指向上一个节点,这样一来。双向链表的遍历时间复杂度最大也就是O(n/2)
- 单向链表的一个缺点就是当我们循环到了末尾时就停止了,做不到继续,而循环链表则完美的解决了 这个问题,他的末尾节点next指向head开始节点,做到了循环。
- python和C语言一样没有专门构造链表的数据结构,但也一样使用其他方式来模仿链表。只不过C语言使用了结构体,python作为一门面向对象的语言使用类 (class)来完成相同的操作,并且更加清晰明白。ps我在一开始就不是很理解C语言的链表我当时以为LNode就是定义的名字,哈哈哈。