数据结构是计算机科学中的一个核心概念,它是指数据的组织、管理和存储方式,以及数据元素之间的关系。
数据结构大致分为几大类:
线性结构
:数组、链表、栈、队列等。
非线性结构
:树、二叉树、堆、图等。
散列
:哈希表。
索引
:
B
树、
B+
树等。
栈:
栈(
stack
),它是一种运算受限的线性表,遵循后进先出(
Last In First Out
,
LIFO
)原则的数据结构。
LIFO(last in first out)
表示就是后进入的元素
,
第一个弹出栈空间
.
类似于自动餐托盘
,
最后放上的托
盘
,
往往先把拿出去使用
.
其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。
向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的
栈顶元素;
从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元
素。
栈的常见操作:
push(element):
添加一个新元素到栈顶位置
.
pop()
:移除栈顶的元素,同时返回被移除的元素。
peek()
:返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)。
isEmpty()
:如果栈里没有任何元素就返回
true
,否则返回
false
。
clear()
:移除栈里的所有元素。
size()
:返回栈里的元素个数。这个方法和数组的
length
属性很类似。
入栈:

出栈:

class Stack:
def __init__(self, size):
self.items = []
self.size = size
def isFull(self):
return len(self.items) == self.size
def push(self, element):
if self.isFull():
raise Exception('stack is full')
self.items.append(element)
def pop(self):
if self.isEmpty():
raise Exception('stack is empty')
return self.items.pop()
def peek(self):
if self.isEmpty():
raise Exception('stack is empty')
return self.items[-1]
def isEmpty(self):
return len(self.items) == 0
def clear(self):
self.items.clear()
if __name__ == '__main__':
stack = Stack(20)
stack.push(1)
stack.push(2)
print(stack.peek())
链表:
链表是一条相互链接的数据节点表。每个节点由两部分组成:数据和指向下一个节点的指针。

优点:
1.
物理存储单元上非连续,而且采用动态内存分配,能够有效的分配和利用内存资源;
2.
节点删除和插入简单,不需要内存空间的重组。
缺点:
1.
不能进行索引访问,只能从头结点开始顺序查找;
2.
数据结构较为复杂,需要大量的指针操作,容易出错。
class Node:
def __init__(self, data=None):
if data is not None:
self.data = data
self.next = None
class LinkedList:
def __init__(self):
head = Node()
self.head = head
def append(self, data):
new_node = Node(data)
# 如果链表为空,则在头部后插入
if self.head.next is None:
self.head.next = new_node
else:
node = self.head.next
while node.next is not None:
node = node.next
node.next = new_node
def prepend(self, data):
new_node = Node(data)
if self.head.next is None:
self.head.next = new_node
else:
new_node.next = self.head.next
self.head.next = new_node
def remove(self, data):
if self.head.next is None:
raise Exception('Linked List is empty')
node = self.head.next
while node.data != data:
node = node.next
node.next = node.next.next
def display(self):
node = self.head.next
while True:
print(node.data)
if node.next is None:
break
node = node.next
if __name__ == '__main__':
list = LinkedList()
list.append(1)
list.append(2)
list.prepend(3)
list.display()
队列:
队列
(Queue)
,它是一种运算受限的线性表
,
先进先出
(FIFO First In First Out)

普通队列:
queue.Queue
是
Python
标准库
queue
模块中的一个类,适用于多线程环境。它实现了线程安全的
FIFO
(先进先出)队列。
import queue
q = queue.Queue()
q.put(1)
q.put(3)
q.put(2)
print(q.qsize())
print(q.get())
print(q.get())
print(q.get())
优先队列:
优先队列(
Priority Queue)是一种特殊的队列,其中的元素按照优先级进行排序。
queue.PriorityQueue
是
Python
标准库
queue
模块中的一个类,适用于多线程环境。它实现了线程安全的优先队列。
import queue
q = queue.PriorityQueue()
# 向队列中添加元素,元素是一个元组 (priority, item),其中 priority 是优先级,item 是实际的数据
q.put((1,'item1'))
q.put((3,'item3'))
q.put((2,'item2'))
print(q.get())
print(q.get())
print(q.get())
双端队列:
双端队列(
Deque
,
Double-Ended Queue
)是一种具有队列和栈性质的数据结构,它允许我们在两端进行元素的添加(push
)和移除(
pop
)操作。在
Python
中,双端队列可以通过
collections
模块中的deque类来实现。
from collections import deque
q = deque()
q.append(1)
q.append(2)
q.appendleft(3)
q.appendleft(4)
print(q.pop())
print(q.popleft())
树:
树(
Tree
)
: n
(
n
≥
0
)个结点构成的有限集合。
当n=0
时,称为空树;
对于任一棵非空树(n> 0
),它具备以下性质:
树中有一个称为“
根(
Root
)
”
的特殊结点,用
root
表示;
其余结点可分为m(m>0)
个互不相交的有限集
T1
,
T2
,
...
,
Tm
,其中每个集合本身又是一棵
树,称为原来树的“
子树(
SubTree
)
”
注意
:
子树之间不可以相交
除了根结点外,每个结点有且仅有一个父结点;
一棵N
个结点的树有
N-1
条边。

树的术语:
1.结点的度(Degree
):结点的子树个数
.
2.
树的度:树的所有结点中最大的度数
. (
树的度通常为结点的个数
N-1)
3.叶子结点(Leaf
):度为
0
的结点
. (
也称为叶子结点
)
4.父结点(Parent
):有子树的结点是其子树的根结点的父结点
5.子结点(Child
):若
A
结点是
B
结点的父结点,则称
B
结点是
A
结点的子结点;子结点也称孩子结
点。
6.兄弟结点(Sibling
):具有同一父结点的各结点彼此是兄弟结点。
7.
路径和路径长度:从结点
n1
到
nk
的路径为一个结点序列
n1 , n2,… , nk, ni
是
ni+1
的父结点。路径
所包含边的个数为路径的长度。
8.结点的层次(Level
):规定根结点在
1
层,其它任一结点的层数是其父结点的层数加
1
。
9.树的深度(Depth
):树中所有结点中的最大层次是这棵树的深度。
二叉树:
二叉树的定义:
二叉树可以为空
,
也就是没有结点
.
若不为空,则它是由根结点和称为其左子树
TL
和右子树
TR
的两个不相交的二叉树组成。
二叉树有五种形态
:

注意
c
和
d
是不同的二叉树
,
因为二叉树是有左右之分的
二叉树有几个比较重要的特性
,
在笔试题中比较常见
:
一个二叉树第 i
层的最大结点数为:
2^(i-1), i >= 1;
深度为k
的二叉树有最大结点总数为:
2^k - 1, k >= 1;
对任何非空二叉树 T
,若
n0
表示叶结点的个数、
n2
是度为
2
的非叶结点个数,那么两者满足
关系n0 = n2 + 1
。
特殊的二叉树:
在二叉树中
,
除了最下一层的叶结点外
,
每层节点都有
2
个子结点
,
就构成了满二叉树
除二叉树最后一层外
,
其他各层的节点数都达到最大个数
. 且最后一层从左向右的叶结点连续存在,
只缺右侧若干节点
.就构成了完全二叉树。

二叉树的存储:
二叉树的存储常见的方式是链表,每个结点封装成一个Node, Node中包含存储的数据, 左结点的引用, 右结点的引用.
二叉树的遍历:
前序遍历(
Pre-order Traversal
)、中序遍历(
In-order Traversal
)和后序遍历(
Post-order
Traversal
)是二叉树的三种基本遍历方式。
遍历规则:
前序遍历,按照以下顺序访问节点:根节点、左子树、右子树。
中序遍历,按照以下顺序访问节点:左子树、根节点、右子树。
后序遍历,按照以下顺序访问节点:左子树、右子树、根节点。
二叉查找树:
二叉查找树(
Binary Search Tree, BST
)是一种特殊的二叉树,它具有以下性质:
1. 每个节点都有一个键值(
key
)。
2. 对于每个节点,其左子树中的所有节点的键值都小于该节点的键值。
3. 对于每个节点,其右子树中的所有节点的键值都大于该节点的键值。
4. 左子树和右子树也分别是二叉查找树。
5. 二叉查找树不允许出现键值相等的结点。

创建二叉查找树结点:
class TreeNode:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
创建二叉查找树类:
class BinarySearchTree:
def __init__(self):
self.root = None
插入结点:
def insert(self, key):
if self.root is None:
self.root = TreeNode(key)
else:
self._insert(self.root, key)
def _insert(self, node, key):
if key < node.key:
if node.left is None:
node.left = TreeNode(key)
else:
self._insert(node.left, key)
elif key > node.key:
if node.right is None:
node.right = TreeNode(key)
else:
self._insert(node.right, key)
查找结点:
def search(self, key):
return self._search(self.root, key)
def _search(self, node, key):
if node is None or node.key == key:
return node
if key < node.key:
return self._search(node.left, key)
return self._search(node.right, key)
删除结点:
def delete(self, key):
self.root = self._delete(self.root, key)
def _delete(self, node, key):
if node is None:
return node
if key < node.key:
node.left = self._delete(node.left, key)
elif key > node.key:
node.right = self._delete(node.right, key)
else:
# 找到要删除的节点
# 情况 1: 节点是叶子节点
if node.left is None and node.right is None:
return None
# 情况 2: 节点只有一个子节点
elif node.left is None:
return node.right
elif node.right is None:
return node.left
# 情况 3: 节点有两个子节点
temp = self._min_value_node(node.right)
node.key = temp.key
node.right = self._delete(node.right, temp.key)
return node
def _min_value_node(self, node):
current = node
while current.left is not None:
current = current.left
return current
中序遍历:
def inorder_traversal(self):
result = []
self._inorder_traversal(self.root, result)
return result
def _inorder_traversal(self, node, result):
if node:
self._inorder_traversal(node.left, result)
result.append(node.key)
self._inorder_traversal(node.right, result)
前序遍历:
def preorder_search(self):
result = []
if self.root is None:
return None
self._preorder_search(self.root, result)
return result
def _preorder_search(self,node,result):
if node is None:
return None
result.append(node.key)
self._preorder_search(node.left,result)
self._preorder_search(node.right,result)
后续遍历:
def inorderr(self):
res = []
self._inorderr(self.root, res)
return res
def _inorderr(self, node, res):
if node is None:
return None
else:
self._inorderr(node.left, res)
self._inorderr(node.right, res)
res.append(node.key)
return res