# 一、链表反转 class ListNode: def __init__(self, x): self.val = x self.next = None def nonrecurse(head): # 循环的方法反转链表 if head is None or head.next is None: return head pre = None cur = head h = head while cur: h = cur tmp = cur.next cur.next = pre pre = cur cur = tmp return h head = ListNode(1) # 测试代码 p1 = ListNode(2) # 创建链表1->2->3->4->None; p2 = ListNode(3) p3 = ListNode(4) head.next = p1 p1.next = p2 p2.next = p3 p = nonrecurse(head) # 输出链表 4->3->2->1->None while p: print(p.val) p = p.next # 二、链表排序 # 快排法 def sortList2(self, head): # write your code here if head is None or head.next is None: return head pivot = head p = pivot l1 = ListNode(0) l2 = ListNode(0) s = l1 f = l2 tmp = head.next while tmp is not None: if tmp.val < pivot.val: s.next = tmp s = s.next elif tmp.val == pivot.val: p.next = tmp p = p.next else: f.next = tmp f = f.next tmp = tmp.next s.next = None f.next = None p.next = None l3 = self.sortList(l1.next) l4 = self.sortList(l2.next) if l3 is not None: l5 = l3 while l5.next is not None: l5 = l5.next l5.next = pivot p.next = l4 return l3 else: p.next = l4 return pivot # 三、链表去重 class Solution: """ @param head: A ListNode @return: A ListNode """ def deleteDuplicates(self, head): if head is None: return head record = {[head.val]} cur, pre = head.next, head while cur: if cur.val in record: pre.next = cur.next cur = cur.next else: record.add(cur.val) pre = pre.next cur = cur.next return head # 四、链表是否闭环 class Node(): # 定义一个Node类,构造两个属性,一个是item节点值,一个是节点的下一个指向 def __init__(self, item=None): self.item = item self.next = None def findbeginofloop(head): # 判断是否为环结构而且查找环结构的入口节点 slowPtr = head # 将头节点赋予slowPtr fastPtr = head # 将头节点赋予fastPtr loopExist = False # 默认环不存在,为False if head == None: # 若是头节点就是空的,那确定就不存在环结构 return False while fastPtr.next != None and fastPtr.next.next != None: # fastPtr的下一个节点和下下个节点都不为空 slowPtr = slowPtr.next # slowPtr每次移动一个节点 fastPtr = fastPtr.next.next # fastPtr每次移动两个节点 if slowPtr == fastPtr: # 当fastPtr和slowPtr的节点相同时,也就是两个指针相遇了 loopExist = True print("存在环结构") break if loopExist == True: slowPtr = head while slowPtr != fastPtr: fastPtr = fastPtr.next slowPtr = slowPtr.next return slowPtr print("不是环结构") return False if __name__ == "__main__": node1 = Node(1) node2 = Node(2) node3 = Node(3) node4 = Node(4) node5 = Node(5) node1.next = node2 node2.next = node3 node3.next = node4 node4.next = node5 node5.next = node2 print(findbeginofloop(node1).item) # 五、合并两个有序链表 class ListNode: def __init__(self, x): self.val = x self.next = None class Solution: def mergeTwoLists(self, l1, l2): """ :type l1: ListNode :type l2: ListNode :rtype: ListNode """ head = ListNode(0) first = head while l1 != None and l2 != None: if l1.val > l2.val: head.next = l2 l2 = l2.next else: head.next = l1 l1 = l1.next head = head.next if l1 == None: head.next = l2 elif l2 == None: head.next = l1 return first.next # 六、求出链表倒数第k个值 def FindKthToTail(self, head, k): # write code here res = [] # 用列表来代替栈 while head: res.append(head) head = head.next if k > len(res) or k < 1: return None return res[-k] # 七、删除链表的当前节点 def removeElements(self, head, val): """ :type head: ListNode :type val: int :rtype: ListNode """ if head: while head.val == val: head = head.next if head is None: return head q = head p = q.next while p: if p.val == val: q.next = p.next else: q = q.next p = p.next return head # 八、链表的中间节点 # 快慢指针,快指针走完,慢指针在中间位置 def midoflist(self, pHead): fast, slow = pHead, pHead while fast and fast.next: # 这个条件很重要,若是设置为fast.next的话会出现Nonetype没有next这个错误。 # fast 在前,若是fast已经为None,那么,fast.next也必定不存在 fast = fast.next.next slow = slow.next print(slow.val) # 九、在一个有环链表中找到环的入口 # 一个从相交的地方走,一个从头走,当相遇的时候,这个相遇的节点就是入口 def circlestart(self, pHead): fast, slow = pHead, pHead while fast and fast.next: fast = fast.next.next slow = slow.next if (fast == slow): break slow = pHead while fast != slow: fast = fast.next slow = slow.next print(fast.val) return fast # 二叉树 class Node(object): """节点类""" def __init__(self, elem=-1, lchild=None, rchild=None): self.elem = elem self.lchild = lchild self.rchild = rchild class Tree(object): """树类""" def __init__(self): self.root = Node() self.myQueue = [] def add(self, elem): """为树添加节点""" node = Node(elem) if self.root.elem == -1: # 若是树是空的,则对根节点赋值 self.root = node self.myQueue.append(self.root) else: treeNode = self.myQueue[0] # 此结点的子树尚未齐。 if treeNode.lchild == None: treeNode.lchild = node self.myQueue.append(treeNode.lchild) else: treeNode.rchild = node self.myQueue.append(treeNode.rchild) self.myQueue.pop(0) # 若是该结点存在右子树,将此结点丢弃。 def front_digui(self, root): """利用递归实现树的先序遍历""" if root == None: return print(root.elem) self.front_digui(root.lchild) self.front_digui(root.rchild) def middle_digui(self, root): """利用递归实现树的中序遍历""" if root == None: return self.middle_digui(root.lchild) print(root.elem) self.middle_digui(root.rchild) def later_digui(self, root): """利用递归实现树的后序遍历""" if root == None: return self.later_digui(root.lchild) self.later_digui(root.rchild) print(root.elem) def front_stack(self, root): """利用堆栈实现树的先序遍历""" if root == None: return myStack = [] node = root while node or myStack: while node: #从根节点开始,一直找它的左子树 print(node.elem) myStack.append(node) node = node.lchild node = myStack.pop() #while结束表示当前节点node为空,即前一个节点没有左子树了 node = node.rchild #开始查看它的右子树 def middle_stack(self, root): """利用堆栈实现树的中序遍历""" if root == None: return myStack = [] node = root while node or myStack: while node: #从根节点开始,一直找它的左子树 myStack.append(node) node = node.lchild node = myStack.pop() #while结束表示当前节点node为空,即前一个节点没有左子树了 print(node.elem) node = node.rchild #开始查看它的右子树 def later_stack(self, root): """利用堆栈实现树的后序遍历""" if root == None: return myStack1 = [] myStack2 = [] node = root myStack1.append(node) while myStack1: #这个while循环的功能是找出后序遍历的逆序,存在myStack2里面 node = myStack1.pop() if node.lchild: myStack1.append(node.lchild) if node.rchild: myStack1.append(node.rchild) myStack2.append(node) while myStack2: #将myStack2中的元素出栈,即为后序遍历次序 print(myStack2.pop().elem) def level_queue(self, root): """利用队列实现树的层次遍历""" if root == None: return myQueue = [] node = root myQueue.append(node) while myQueue: node = myQueue.pop(0) print(node.elem) if node.lchild != None: myQueue.append(node.lchild) if node.rchild != None: myQueue.append(node.rchild) if __name__ == '__main__': """主函数""" elems = range(10) #生成十个数据做为树节点 tree = Tree() #新建一个树对象 for elem in elems: tree.add(elem) #逐个添加树的节点 print('队列实现层次遍历:') tree.level_queue(tree.root) print('\n\n递归实现先序遍历:') tree.front_digui(tree.root) print('\n递归实现中序遍历:') tree.middle_digui(tree.root) print('\n递归实现后序遍历:') tree.later_digui(tree.root) print('\n\n堆栈实现先序遍历:') tree.front_stack(tree.root) print('\n堆栈实现中序遍历:') tree.middle_stack(tree.root) print('\n堆栈实现后序遍历:') tree.later_stack(tree.root)
时间复杂度 / 空间复杂度:分别用来评估算法运行效率和内存占用大小的式子。node
### 递归的两个特色:python
1. 调用自身
2. 结束条件算法
```python
def func(x):
if x > 0:
func(x - 1)
print(x)数据库
func(5)
# 1,2,3,4,5 递归调用func,递归结束后,从内至外print(x)
```数组
### 斐波那契数列:
```python
a = 0
b = 1
while b < 1000:
print(b)
a, b = b, a + b
```
```python
li = []
for i in range(20):
if i == 0 or i == 1:
li.append(1)
else:
li.append(li[i-1] + li[i-2])数据结构
print(li)
```
### 台阶例子:app
```python
# 有20级台阶的楼梯,一次能够迈一级或两级台阶,那么爬完此楼梯有几种方法?
li = []
for i in range(20):
if i == 0:
li.append(1) # 一级台阶1种走法
elif i == 1:
li.append(2) # 二级台阶2种走法
else:
li.append(li[i - 2] + li[i - 1]) # 后一级台阶的走法是前两级走法之和
print(li)dom
# [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946]
```函数
```python
# 一楼梯共有20级台阶,规定每步能够迈1级台阶或2级台阶或3级台阶,那么爬完此楼梯有几种方法?oop
li = [] # 一、二、3级台阶分别有一、二、4种走法
for i in range(20):
if i == 0:
li.append(1)
elif i == 1:
li.append(2)
elif i == 2:
li.append(4)
else:
li.append(li[i-3] + li[i-2] + li[i-1]) # 后一级台阶的走法是前三级走法之和
print(li)
# [1, 2, 4, 7, 13, 24, 44, 81, 149, 274, 504, 927, 1705, 3136, 5768, 10609, 19513, 35890, 66012, 121415]
```
### 二分查找
针对的是有序列表。从有序列表的候选区data[0:n]开始,经过对待查找的值与候选区中间值的比较,可使候选区减小一半。
```python
def bin_search(data,value):
low = 0
high = len(data) - 1
while low <= high:
mid = (low + high) // 2
if data[mid] == value:
return mid
elif data[mid] > value:
high = mid -1
else:
low = mid + 1
else:
return "查无此值"
li = list(range(1,10))
print(bin_search(li,5))
```
### 递归版二分查找
```python
def bin_search_rec(data, value, low, high):
if low <= high:
mid = (low + high) // 2
if data[mid] == value:
return mid
elif data[mid] > value:
return bin_search_rec(data, value, low, mid - 1)
else:
return bin_search_rec(data, value, mid + 1, high)
else:
return "查无此值"
li = list(range(1, 10))
high = len(li) - 1
print(bin_search_rec(li, 6, 0, high))
```
### 列表排序
将无序列表变为有序列表。
```python
排序low B三人组:
冒泡排序 # 重点掌握
选择排序
插入排序
排序NB三人组:
快速排序 # 重点掌握
堆排序
归并排序
基本无人用的排序(了解):
基数排序
希尔排序
桶排序
```
### 冒泡排序
关键点:趟 | 无序区。
```python
def bubble_sort(li):
# 趟
for i in range(len(li) - 1):
# 无序区
for j in range(len(li) - i - 1):
if li[j] > li[j + 1]:
li[j], li[j + 1] = li[j + 1] , li[j]
import random
li = list(range(1, 11))
random.shuffle(li)
bubble_sort(li)
print(li)
时间复杂度:O(n2),空间复杂度O(1)
```
冒泡排序--优化。若是冒泡排序中执行一趟而没有交换,则列表已是有序状态,能够直接结束算法。
```python
def bubble_sort(data):
# 趟
for i in range(len(data) - 1):
exchange = False
# 无序区
for j in range(len(data) - i - 1):
if data[j] > data[j + 1]:
data[j], data[j + 1] = data[j + 1], data[j]
exchange = True
if not exchange:
return
import random
li = list(range(1, 16))
random.shuffle(li)
bubble_sort(li)
print(li)
```
### 快速排序
快排思路:
1. 取一个元素p(第一个元素),使元素p归位;
2. 列表被p分为两部分,左边都比p小,右边都比p大;
3. 递归完成排序。
关键点:整理 | 递归
```python
# 分割函数
def partition(data, left, right):
tem = data[left]
while left < right:
while left < right and data[right] >= tem:
right -= 1
data[left] = data[right]
while left < right and data[left] <= tem:
left += 1
data[right] = data[left]
data[left] = tem
return left
def quick_sort(data, left, right):
if left < right:
mid = partition(data, left, right)
quick_sort(data, left, mid - 1)
quick_sort(data, mid + 1, right)
li = list(range(1, 11))
import random
random.shuffle(li)
quick_sort(li, 0, len(li) - 1)
print(li)
时间复杂度O(nlogn),空间复杂度:平均状况O(logn) | 最坏状况O(n)
```
### 二叉树
二叉树:度不超过2的树(节点最多有两个叉);
满二叉树:一个二叉树,若是每一层的节点数都达到最大值,则这个二叉树就是满二叉树;
彻底二叉树:叶节点只能出如今最下层和次下层,而且最下面一层的节点都集中在该层最左边若干位置的二叉树。
```python
# 二叉树的存储方式:链式存储方式;顺序存储方式(列表)。
父节点和左孩子节点的编号下标的关系:
2i+ 1;
父节点和右孩子节点的编号下标的关系:
2i + 2;
# (彻底)二叉树能够利用列表来存储,经过规律能够从父亲找到孩子或从孩子找到父亲。
```
### 堆
大根堆:一颗彻底二叉树,知足任一节点都比其孩子节点大;
小根堆:一个彻底二叉树,知足任一节点都比其孩子节点小。
# 数据结构
数据结构是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。
简单来讲,数据结构就是设计数据以何种方式组织并存储在计算机中。
程序 = 数据结构 + 算法
数据结构按照其逻辑结构可分为线性结构、树结构、图结构:
1. 线性结构:数据结构中的元素存在一对一的相互关系;
2. 树结构:数据结构中的元素存在一对多的相互关系;
3. 数据结构中的元素存在多对多的相互关系。
### 栈
```
栈(Stack)是一个数据集合,能够理解为只能在一端进行插入或删除操做的列表。
栈的特色:后进先出(last-in, first-out)
栈的概念:栈顶、栈底
栈的基本操做:进栈(压栈)push 出栈pop 取栈顶gettop
```
### 队列
```
队列(Queue)是一个数据集合,仅容许在列表的一端进行插入,另外一端进行删除。
进行插入的一端称为队尾(rear),插入动做称为进队或入队
进行删除的一端称为队头(front),删除动做称为出队
队列的性质:先进先出(First-in, First-out)
双向队列:队列的两端都容许进行进队和出队操做。
队列的实现原理:环形队列
```
```python
# Python处理队列的模块
from collections import deque
# Python处理堆的模块
import heapq
```
### 链表
链表中每个元素都是一个对象,每一个对象称为一个节点,包含有数据域key和指向下一个节点的指针next。经过各个节点之间的相互链接,最终串联成一个链表。
```python
# 节点定义
class Node(object):
def __init__(self,item):
self.item = item
self.next = None
```
双链表中每一个节点有两个指针:一个指向后面节点、一个指向前面节点。
```python
class Node(object):
def __init__(self, item=None):
self.item = item
self.next = None
self.prior = None
```
###哈希表
哈希表是一个经过哈希函数来计算数据存储位置的数据结构。一般支持以下操做:
* insert(key, value):插入键值对(key,value)
* get(key):若是存在键为key的键值对则返回其value,不然返回空值
* delete(key):删除键为key的键值对
```
哈希表(Hash Table,又称为散列表),是一种线性表的存储结构。
哈希表由一个直接寻址表和一个哈希函数组成。哈希函数h(k)将元素关键字k做为自变量,返回元素的存储下标。
```
因为哈希表的大小是有限的,而要存储的值的总数量是无限的,所以对于任何哈希函数,都会出现两个不一样元素映射到同一个位置上的状况,这种状况叫作哈希冲突。
好比:h(k)=k mod 7, h(0)=h(7)=h(14)=...
解决哈希冲突
开放寻址法:若是哈希函数返回的位置已经有值,则能够向后探查新的位置来存储这个值。
拉链法:哈希表每一个位置都链接一个链表,当冲突发生时,冲突的元素将被加到该位置链表的最后。
字典与集合都是经过哈希表来实现的。
### 二叉树
二叉树的链式存储:将二叉树的节点定义为一个对象,节点之间经过相似链表的连接方式来链接。
**二叉树的遍历**
对于二叉树,有深度遍历和广度遍历,深度遍历有前序、中序以及后序三种遍历方法,广度遍历即咱们日常所说的层次遍历。
要点:递归思想,每一级子树都遵循这个规则。
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:只需按层次遍历便可
二叉搜索树是一颗二叉树且知足性质:设x是二叉树的一个节点。若是y是x左子树的一个节点,那么y.key ≤ x.key;若是y是x右子树的一个节点,那么y.key ≥ x.key.
平均状况下,二叉搜索树进行搜索的时间复杂度为O(nlogn)。
```AVL树:AVL树是一棵自平衡的二叉搜索树。B树(B-Tree):B树是一棵自平衡的多路搜索树。经常使用于数据库的索引。```