跳到正文
全部文章

常用算法的实现

整理排序、查找、链表、字符串与组合问题等常见算法的 Python 实现和笔记。

算作自己的一次复习

排序

冒泡排序

C语言

#include <stdbool.h>
#include <stdio.h>
#define GET_ARRAY_LEN(array, len) {len = (sizeof(array) / sizeof(array[0]));}
void bubbleSort(int a[], int count) {
int index, temp;
bool flag = true;
for (index = 1; index <= count; index++) {
for (int pos = 0; pos < count - index; pos++) {
if (a[pos] > a[pos + 1]) {
temp = a[pos];
a[pos] = a[pos + 1];
a[pos + 1] = temp;
flag = false;
}
}
if (flag) {
break;
}
}
}
void main() {
int a[] = {1, 2, 323423, 234, 43652, 234, 24, 6457, 7457, 35, 23};
int len;
GET_ARRAY_LEN(a, len);
bubbleSort(a, len);
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
}

python

#!/usr/bin/python
# -*- coding: utf-8 -*-
def bubble_sort(r_list):
flag = True
for index in range(len(r_list)-1, 0, -1):
if flag:
flag = False
for i in range(index):
if r_list[i] > r_list[i+1]:
r_list[i], r_list[i+1] = r_list[i+1], r_list[i]
flag = True
if __name__ == '__main__':
test_list = [4, 6, 9, 11, 3, 2, 0]
bubble_sort(test_list)
print test_list

插入排序

python 递归版本

def insert_sort(r_list):
r_len = len(r_list)
if r_len > 1:
r_list = insert_sort(r_list[:r_len-1]) + [r_list[-1]]
else:
return r_list
i = r_len - 1
while i > 0:
j = i - 1
if r_list[j] > r_list[i]:
r_list[i], r_list[j] = r_list[j], r_list[i]
i -= 1
return r_list

python another version

def insert_sort(r_list, r_len=None):
if r_len is None:
r_len = len(r_list)
if r_len > 1:
insert_sort(r_list, r_len-1)
else:
return
i = r_len - 1
j, temp = i, r_list[i]
while j > 0 and temp < r_list[j-1]:
r_list[j] = r_list[j-1]
j -= 1
r_list[j] = temp

堆排序

使用官方库

import heapq
data = [9, 3, 5, 7, 2, 4, 6, 8, 0]
result = []
heapq.heapify(data)
while data:
result.append(heapq.heappop(data))
return result

自己写

def heap_adjust(heap, i, h_len):
while 2 * i + 1 < h_len:
child = 2 * i + 1
if child + 1 < h_len:
if heap[child] < heap[child + 1]:
child += 1
if heap[i] < heap[child]:
heap[i], heap[child] = heap[child], heap[i]
i = child
else:
break
def heap_sort(heap):
n = len(heap)
for x in reversed(xrange(n // 2)):
heap_adjust(heap, x, n)
for y in xrange(n-1, 0, -1):
heap[0], heap[y] = heap[y], heap[0]
heap_adjust(heap, 0, y)

快速排序

def qsort(L):
if len(L) <= 1: return L
return qsort([lt for lt in L[1:] if lt < L[0]]) + [L[0]] + qsort([ge for ge in L[1:] if ge >= L[0]])

线性排序

主要有计数排序、桶排序和基数排序,均为稳定算法

查找

查找数组中的最大值和最小值

思路:

  1. 数组中的元素每两个进行一组一次比较,较大元素放到大元素表中,较小元素放到小元素表中,分组的复杂度n/2

  2. 在小元素表中逐个比较找到最小值即整个数组的最小值,复杂度n/2;在大元素表中逐个比较找到最大值,即数组的最大值,复杂度也是n/2

总的复杂度3n/2,代码如下

def find_max_and_min(r_list):
r_len = len(r_list)
if r_len < 1:
return (None,) * 2
if r_len % 2 == 0:
start = 2
max_item, min_item = r_list[0], r_list[1]
if max_item < min_item:
max_item, min_item = min_item, max_item
else:
max_item, min_item = (r_list[0],) * 2
start = 1
while start < r_len:
min_test, max_test = r_list[start], r_list[start + 1]
if min_test > max_test:
min_test, max_test = max_test, min_test
if min_test < min_item:
min_item = min_test
if max_test > max_item:
max_item = max_test
start += 2
return max_item, min_item

二分查找

使用官方库

from bisect import bisect_left
def binary_search(a, x, low=0, high=None):
high = high if high is not None else len(a) # hi defaults to len(a)
pos = bisect_left(a, x, low, high)
return (pos if pos != high and a[pos] == x else -1)

自己写

def binary_search(r_list, target):
low, high = 0, len(r_list)
while low <= high:
mid = (low + high) // 2
if r_list[mid] == target:
return mid
elif r_list[mid] > target:
high = mid - 1
else:
low = mid + 1
return -1

用递归写

def binary_search(r_list, target, low=0, high=None):
if high is None:
high = len(r_list)
if low <= high:
mid = (low + high) // 2
mid_val = r_list[mid]
if mid_val == target:
return mid
elif mid_val > target:
return binary_search(r_list, target, low, mid-1)
else:
return binary_search(r_list, target, low+1, high)
else:
return -1

链表

反转单链表

主要设置好变量,这个不难,所以一般会要求写得快又准

class Node(object):
def __init__(self, data=None):
self.data = data
self.next = None
def reverse(r):
if r.next is None:
return r
head = r
cur = r.next
tail = r # new linked node tail, will return as new head
while cur:
tmp = cur.next
head.next = tmp
cur.next = tail
tail = cur
cur = tmp
return tail
def print_node(x):
link_list = []
while x:
link_list.append(x.data)
x = x.next
print ' -> '.join(map(str, link_list))
def main():
a = Node(1)
a.next = Node(2)
a.next.next = Node(3)
print_node(a)
print
b = reverse(a)
print_node(b)
if __name__ == '__main__':
main()

字符串

最长公共子串

代码来自英文维基,原理是构造矩阵,找最长的对角线连续不为0的长度

def longest_common_substring(s1, s2):
m = [[0] * (1 + len(s2)) for i in xrange(1 + len(s1))]
longest, x_longest = 0, 0
for x in xrange(1, 1 + len(s1)):
for y in xrange(1, 1 + len(s2)):
if s1[x - 1] == s2[y - 1]:
m[x][y] = m[x - 1][y - 1] + 1
if m[x][y] > longest:
longest = m[x][y]
x_longest = x
else:
m[x][y] = 0
return s1[x_longest - longest: x_longest]

最长公共子序列

不要求字符是连续的,下面解法有最大递归1000的限制,所以还是使用自顶向上的DP更好一点,有兴趣可以看这里

def memoize(fn):
cache = dict()
def wrapped(*v):
key = tuple(v) # tuples are hashable, and can be used as dict keys
if key not in cache:
cache[key] = fn(*v)
return cache[key]
return wrapped
def lcs(xs, ys):
@memoize
def lcs_(i, j):
if i and j:
xe, ye = xs[i-1], ys[j-1]
if xe == ye:
return lcs_(i-1, j-1) + [xe]
else:
return max(lcs_(i, j-1), lcs_(i-1, j), key=len)
else:
return []
return lcs_(len(xs), len(ys))

最大子序列

待续

排列与组合

组合

通常的实现是10置换法

def combinations(iterable, r):
# combinations('ABCD', 2) --> AB AC AD BC BD CD
# combinations(range(4), 3) --> 012 013 023 123
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i+1, r):
indices[j] = indices[j-1] + 1
yield tuple(pool[i] for i in indices)

排列

其实就是将组合得到的每个分组进行全排列

def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = range(n)
cycles = range(n, n-r, -1)
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return

这两段代码里都用到了for...else的语句结构,return放不放在else下的区别是,当for循环里break时,可以跳过return,否则必须经过return。当经过完所有for的条件后,将会返回 这两段代码的结果都是字典序由小到大


原文发布于 SegmentFault