转载请注明出处:
http://blog.csdn.net/BruceHurrican/article/details/76535719
最近在学习《算法图解》,写下此文当作学习笔记了。
大O可以比较操作数,指出算法运行时间的增速。
算法运行时间是从其增速的角度度量的。
1.O(log n), 也叫对数时间,这样的算法包括二分查找法
2.O(n), 也叫线性时间,这样的算法包括简单查找法
3.O(n * log n), 快速排序——速度较快
4.O(n^2),选择排序——速度较慢
5.O(n!), 算法非常慢
需要数组或列表有序。
二分查找法,python2.7实现如下:
# encoding=utf-8
# 二分查找法
def binary_search(list, item):
low = 0
high = len(list) - 1; # 获取 list 最后一个元素索引
while low <= high:
mid = (low + high)/2
guess = list[mid] # 取出列表中位置是 mid 的元素
print guess
if guess == item:
print str(item) + " 在列表中的位置索引是: " + str(mid)
return mid
if guess > item:
high = mid - 1
else:
low = mid + 1
print str(item) + " 不在列表中"
return None
print "====测试二分查找===="
myList = range(1,100,2) # 列表必须是有序的
# for x in myList:
# print "列表值: " + str(x)
binary_search(myList, 83)
# binary_search(myList, -2)
# binary_search(myList, 9)
print "================华丽丽的分隔线==================="
#================华丽丽的分隔线===================
运行结果如下:
====测试二分查找====
49
75
87
81
83
83 在列表中的位置索引是: 41
49
23
11
5
1
-2 不在列表中
49
23
11
5
7
9
9 在列表中的位置索引是: 4
================华丽丽的分隔线===================
java实现如下:
public static void main(String[] args) {
System.out.println("===测试二分查找===");
List list = new ArrayList<>(100);
for (int i = 1; i <= 100 ; i+=2) {
list.add(i);
}
binarySearch(list, 13);
binarySearch(list, 34);
binarySearch(list, 87);
// Java 默认方法
System.out.println("13在列表中的索引: " + Collections.binarySearch(list, 13));
System.out.println("34在列表中的索引: " + Collections.binarySearch(list, 34));
System.out.println("87在列表中的索引: " + Collections.binarySearch(list, 87));
}
/** * 二分查找法 * @param dataList 有序集合 * @param searchNum 被搜索的数值 * @return searchNume 在 dataList 中的索引 */
private static int binarySearch(List dataList, int searchNum) {
int low = 0;
int high = dataList.get(dataList.size() - 1);
while (low <= high) {
int mid = (low + high) >>> 2;
int guess = dataList.get(mid);
System.out.println("guess: " + guess);
if (guess == searchNum) {
System.out.println(searchNum + " 在列表中的索引是: " + mid);
return mid;
}
if (guess > searchNum) {
high = mid - 1;
} else {
low = mid + 1;
}
}
System.out.println(searchNum + " 不在列表中");
return -1;
}
运行结果为:
===测试二分查找===
guess: 99
guess: 49
guess: 23
guess: 11
guess: 17
guess: 13
13 在列表中的索引是: 6
guess: 99
guess: 49
guess: 23
guess: 35
guess: 29
guess: 31
guess: 33
34 不在列表中
guess: 99
guess: 49
guess: 73
guess: 85
guess: 91
guess: 87
87 在列表中的索引是: 43
13在列表中的索引: 6
34在列表中的索引: -18
87在列表中的索引: 43
从代码中可以看到,java类自带有二分查找实现,实际工作中并不需要我们编写算法实现,java自带类路径为 java.util.Collections
kotlin 实现
object KK{
@JvmStatic fun main(args: Array){
println("===测试二分查找===")
val dataList = listOf(1,3,5,7,9)
binarySearch(dataList, 3)
binarySearch(dataList, -2)
binarySearch(dataList, 7)
println("3在dataList中的索引: " + dataList.binarySearch(3))
println("-2在dataList中的索引: " + dataList.binarySearch(-2))
println("7在dataList中的索引: " + dataList.binarySearch(7))
}
/*** * 二分查找 * dataList 有序集合 * searchNum 查找数值 * return searchNum 在 dataList 中的索引 */
private fun binarySearch(dataList: List, searchNum: Int): Int {
var low = 0
var high = dataList.get(dataList.size - 1)
while (low <= high) {
var mid = (low + high) / 2
var guess = dataList.get(mid)
println("guess: " + guess)
if (guess == searchNum) {
println(String.format("%d 在列表中的索引是: %d", searchNum, mid))
return mid
}
if (guess > searchNum) {
high = mid - 1
} else {
low = mid + 1
}
}
println(String.format("%d 不在集合中", searchNum))
return -1
}
}
运行结果为:
===测试二分查找===
guess: 9
guess: 3
3 在列表中的索引是: 1
guess: 9
guess: 3
guess: 1
-2 不在集合中
guess: 9
guess: 3
guess: 5
guess: 7
7 在列表中的索引是: 3
3在dataList中的索引: 1
-2在dataList中的索引: -1
7在dataList中的索引: 3
kotlin也同样提供了二分查找方法,在kotlin-stdlib-1.1.2-4包中,kotlin.collections.Collections.kt中
数组 | 链表 |
---|---|
读取 | O(1) |
插入 | O(n) |
删除 | O(n) |
是一种灵巧的算法,速度不是很快,运行时间为O(n^n)
python2.7实现如下:
# 选择数组中最小的数
def findSmallest(arr):
smallest = arr[0]
smallest_index = 0
for i in range(1, len(arr)):
if arr[i] < smallest:
smallest = arr[i]
smallest_index = i
return smallest_index
# 对数组排序
def selectionSort(arr):
newArr = []
for i in range(len(arr)):
smallest = findSmallest(arr)
newArr.append(arr.pop(smallest))
return newArr
print "===测试选择排序==="
selectionList = [54,32,1,3,4,78,65]
# selectionList.sort()
# print selectionList
print "排序后的集合为: " + str(selectionSort(selectionList))
运行结果:
===测试选择排序===
排序后的集合为: [1, 3, 4, 32, 54, 65, 78]
对于选择排序python提供了默认实现 list.sort()
java 实现:
public static void main(String[] args) {
List testList = new ArrayList<>();
testList.add(33);
testList.add(14);
testList.add(6);
testList.add(15);
testList.add(56);
testList.add(84);
testList.add(38);
testList.add(97);
testList.add(8);
testList.add(19);
System.out.println("原集合中各元素: ");
for (int i = 0; i < testList.size(); i++) {
System.out.print(testList.get(i) + ", ");
}
System.out.println();
System.out.println("排序后");
List newList = selectionSort(testList);
for (int i = 0; i < newList.size(); i++) {
System.out.print(newList.get(i) + ", ");
}
}
/** * 将列表从小到大排列并生成新列表 * @param arr * @return */
private static List selectionSort(List arr) {
List newList= new ArrayList<>(arr.size());
int size = arr.size();
for (int i = 0; i < size; i++) {
int smallIndex = findSmallestIndex(arr);
newList.add(arr.get(smallIndex));
arr.remove(smallIndex);
}
return newList;
}
/** * 获取最小值的索引 * @param arr * @return */
private static int findSmallestIndex(List arr) {
int smallest = arr.get(0);
int smallestIndex = 0;
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) < smallest) {
smallest = arr.get(i);
smallestIndex = i;
}
}
return smallestIndex;
}
结果如下:
原集合中各元素:
33, 14, 6, 15, 56, 84, 38, 97, 8, 19,
排序后
6, 8, 14, 15, 19, 33, 38, 56, 84, 97,
确定基线条件和递归条件是关键,比选择排序快。快速排序的性能高度依赖于选择的基准值。
python2.7实现如下:
# encoding=utf-8
# 快速排序
def quickSort(arr, keyIndex):
if len(arr) < 2:
return arr #基线条件,为空或只包含一个元素的数组是有序数组
else:
if keyIndex <= len(arr) - 1:
pivot = arr[keyIndex]
else:
pivot = arr[0]
arr.remove(pivot)
less = [i for i in arr if i <= pivot] # 由所有小于基准值的元素组成的子数组
greater = [i for i in arr if i> pivot] # 同所有大于基准值的元素组成的子数组
return quickSort(less, keyIndex) + [pivot] + quickSort(greater, keyIndex)
print "===测试快速排序==="
print quickSort([34,2,133,38,45,3,15,21,98], 3)
运行结果如下:
===测试快速排序===
[2, 3, 15, 21, 34, 38, 45, 98, 133]
下面这个例子是《啊哈!算法》中的解密QQ号
# encoding=utf-8
def guessQQ(arr):
temp = []
while len(arr) > 1:
temp.append(arr[0])
a = arr[1]
arr.remove(arr[0])
if len(arr) > 1:
arr.remove(arr[0])
arr.append(a)
else :
temp.append(arr[0])
return temp
qq = [6,3,1,7,5,8,9,2,4]
print "加密QQ号:" + "".join(str(x) for x in qq)
print "解密QQ号:" + "".join(str(x) for x in guessQQ(qq))
运行结果:
加密QQ号:631758924
解密QQ号:615947283
使用散列函数和数组创建的一种数据结构。当key出现冲突时,对于相同数组索引通过链表解决数据冲突。散列表的查找、插入和删除速度都很快,适合用于模拟映射关系,数据去重。
散列函数,无论给它什么数据,它都返回一个数字
要求:
特点:
- 散列函数总是将同样的输入映射到相同的索引。
- 散列函数将不同的输入映射到不同的索引。
- 散列函数知道数组有多大,只返回有效的索引。
python2.7中提供的散列表是字典,Java中提供的是HashMap
python2.7实现如下:
# 散列表
voted = {}
def check_voter(name):
if voted.get(name):
print "%s has voted" % name
else:
print "let %s vote" % name
voted[name] = hash(name)
check_voter("bruce")
check_voter("max")
check_voter("tom")
check_voter("bruce")
check_voter("max")
运行结果:
let bruce vote
let max vote
let tom vote
bruce has voted
max has voted
解决最短路径问题的算法被称为广度优先搜索。用于在非加权图中查找最短路径。
例子:
开发android需要掌握java、xml、json等,开发ios需要掌握object-c、swift、json等,开发h5需要掌握 css、html、javascript等。
岗位 | 技能1 | 技能2 | 技能3 |
---|---|---|---|
android | json | java | json |
ios | object-c | swift | json |
h5 | css | html | javascript |
python2.7实现如下:
# encoding=utf-8
# 广度优先搜索
from collections import deque
def learnFirstLanguage(firstLanguage):
return firstLanguage == "java"
lesson = {}
lesson["android"] = ["xml","java","json"]
lesson["ios"] = ["object-c", "swift", "json"]
lesson["h5"] = ["css", "javascript", "html"]
lesson["xml"] = []
lesson["java"] = []
lesson["json"] = []
lesson["object-c"] = []
lesson["swift"] = []
lesson["html"] = []
lesson["css"] = []
lesson["javascript"] = []
def searchFirstToLearn(target):
searchQueue = deque()
searchQueue += lesson[target]
searched = []
while searchQueue:
subject = searchQueue.popleft()
if not subject in searched:
if learnFirstLanguage(subject):
print "%s is your first lesson to learn" % subject
return True
else:
searchQueue += lesson[subject]
searched.append(subject)
return False
searchFirstToLearn("android")
运行结果:
java is your first lesson to learn
用于在加权图中查找最小的路径。仅当权重为正时,狄克斯特拉算法才有效,如果图中包含负边,应该使用贝尔曼-福德算法。
四个步骤:
1.找出“最便宜”的节点,即可在最短时间内到达的节点
2.更新该节点的邻居的开销
3.重复这个过程,直到对图中的每个节点都这样做了
4.计算最终最短路径
python2.7实现如下:
# encoding=utf-8
# 贪婪算法
foods = set(["beef", "pork", "apple", "orange", "milk", "hamburger", "fried chicken legs", "sushi"])
choices = {}
choices["fruit"] = set(["apple", "orange"])
choices["meat"] = set(["beef", "pork"])
choices["fastFood"] = set(["hamburger", "fried chicken legs"])
choices["drink"] = set(["milk"])
choices["c1"] = set(["sushi"])
choices["c2"] = set(["sushi" , "hamburger"])
choices["breakfast"] = set(["apple", "milk"])
choices["dinner"] = set(["beef", "sushi"])
choices["visitor"] = set(["pork", "sushi","orange"])
choices["kids"] = set(["fried chicken legs", "milk","orange", "apple"])
choices["young"] = set(["hamburger", "milk", "apple"])
bestChoices = set()
while foods:
best = None
foodCovered = set()
for a,b in choices.items():
covered = foods & b
if len(covered) > len(foodCovered):
best = a
foodCovered = covered
foods -= foodCovered
bestChoices.add(best)
print "最优选择: "
print bestChoices
运行结果:
最优选择:
set([‘c2’, ‘kids’, ‘meat’])
KNN(K-nearest neighbours),机器学习思路之一,能否挑选合适的特征事关KNN算法的成败。未来不确定因素太多,无法根据股市过往表现来预测股市。
核心是双重嵌套循环,时间复杂度是O(N^2)。
python2.7实现如下:
# encoding=utf-8
# 冒泡排序
def bubbleSort(a):
asize = len(a)
for i in xrange(asize - 1):
for j in xrange(asize - 1 - i):
if a[j] > a[j+1]:
a[j], a[j+1] = a[j+1], a[j]
return a
testList = [32,12,2,156,35,67,89,73,21,9,47,82]
print "原列表:"
print testList
print "排序后:"
print bubbleSort(testList)
运行结果:
原列表:
[32, 12, 2, 156, 35, 67, 89, 73, 21, 9, 47, 82]
排序后:
[2, 9, 12, 21, 32, 35, 47, 67, 73, 82, 89, 156]
bookCode