每个程序员都应该知道的8大算法
Posted 技术小张zz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每个程序员都应该知道的8大算法相关的知识,希望对你有一定的参考价值。
在编程开发中,算法是用于解决特定问题或完成特定任务的一组指令或过程。算法可以用任何编程语言表示,可以像一系列基本操作一样简单,也可以像涉及不同数据结构和逻辑的多步骤过程一样复杂。
算法的主要目标是接收输入、处理它并提供预期的输出。算法可以根据时间和空间复杂性、用于解决问题的技术以及解决问题的类型进行分类。算法的例子有排序、搜索、图形遍历、字符串操作、数学运算等等。
这些算法广泛用于各种应用程序,程序员对它们有深刻的理解很重要,所以我会尽力解释它们。
我们将要讨论的8大算法如下:
1、排序算法:
1).Quicksort:
Quicksort 是一种分而治之的算法,它从数组中选择一个“主元”元素,然后根据其他元素是小于还是大于主元将它们分成两个子数组。然后对子数组进行递归排序。
def quicksort(arr):
if len(arr) <= 1:
return arr
pivot = arr[len(arr) // 2]
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return quicksort(left) + middle + quicksort(right)
print(quicksort([3,6,8,10,1,2,1]))
2).归并排序:
归并排序算法是一种分而治之的算法,它将一个数组一分为二,对两半进行排序,然后将它们归并在一起。
def merge_sort(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort(arr[:mid])
right = merge_sort(arr[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = 0
j = 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
result += left[i:]
result += right[j:]
return result
print(merge_sort([3,6,8,10,1,2,1]))
3).堆排序:
堆排序算法是一种基于比较的排序算法,它将输入元素构建一个堆,然后从堆中反复提取最大元素,并将其放在排序后的输出数组的末尾。
def heap_sort(arr):
n = len(arr)
for i in range(n, -1, -1):
heapify(arr, n, i)
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i]
heapify(arr, i, 0)
def heapify(arr, n, i):
largest = i
l = 2 * i + 1
r = 2 * i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
print(heap_sort([3,6,8,10,1,2,1]))
2.搜索算法:
1).二分搜索:
二分搜索是一种从已排序的项目列表中查找项目的有效算法。它的工作原理是将要搜索的数组部分重复def binary_search(arr, x):
分成两半,直到找到目标值。
def binary_search(arr, x):
low = 0
high = len(arr) - 1
mid = 0
while low <= high:
mid = (high + low) // 2
if arr[mid] < x:
low = mid + 1
elif arr[mid] > x:
high = mid - 1
else:
return mid
return -1
print(binary_search([1,2,3,4,5,6,7], 4))
2).哈希表:
哈希表是一种将键映射到值的数据结构,使用哈希函数计算到桶或槽数组的索引,从中可以找到所需的值。
class HashTable:
def __init__(self):
self.size = 10
self.keys = [None] * self.size
self.values = [None] * self.size
def put(self, key, data):
index = self.hash_function(key)
while self.keys[index] is not None:
if self.keys[index] == key:
self.values[index] = data # update
return
index = (index + 1) % self.size
self.keys[index] = key
self.values[index] = data
def get(self, key):
index = self.hash_function(key)
while self.keys[index] is not None:
if self.keys[index] == key:
return self.values[index]
index = (index + 1) % self.size
return None
def hash_function(self, key):
sum = 0
for pos in range(len(key)):
sum = sum + ord(key[pos])
return sum % self.size
t = HashTable()
t.put("apple", 10)
t.put("orange", 20)
t.put("banana", 30)
print(t.get("orange"))
3.图算法:
1).Dijkstra 最短路径算法:
Dijkstra 最短路径算法是一种寻找图中节点之间最短路径的算法。
import heapq
def dijkstra(graph, start):
heap = [(0, start)]
visited = set()
while heap:
(cost, v) = heapq.heappop(heap)
if v not in visited:
visited.add(v)
for u, c in graph[v].items():
if u not in visited:
heapq.heappush(heap, (cost + c, u))
return visited
graph =
'A': 'B': 2, 'C': 3,
'B': 'D': 4, 'E': 5,
'C': 'F': 6,
'D': 'G': 7,
'E': 'G': 8, 'H': 9,
'F': 'H': 10,
'G': ,
'H':
print(dijkstra(graph, 'A'))
4.动态规划:
斐波那契数列:
斐波那契数列是可以使用动态规划解决的问题的经典示例。
def fibonacci(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10))
5.贪婪算法:
霍夫曼编码:
霍夫曼编码是一种无损数据压缩算法,它使用贪婪算法为给定的一组符号构造前缀码。
from collections import Counter, namedtuple
def huffman_encoding(data):
"""
Generates a Huffman encoded string of the input data
"""
# Create a frequency counter for the data
freq_counter = Counter(data)
# Create a namedtuple for the Huffman tree nodes
HuffmanNode = namedtuple("HuffmanNode", ["char", "freq"])
# Create a priority queue for the Huffman tree
priority_queue = PriorityQueue()
# Add all characters to the priority queue
for char, freq in freq_counter.items():
priority_queue.put(HuffmanNode(char, freq))
# Combine nodes until only the root node remains
while priority_queue.qsize() > 1:
left_node = priority_queue.get()
right_node = priority_queue.get()
combined_freq = left_node.freq + right_node.freq
combined_node = HuffmanNode(None, combined_freq)
priority_queue.put(combined_node)
# Generate the Huffman code for each character
huffman_code =
generate_code(priority_queue.get(), "", huffman_code)
# Encode the input data
encoded_data = ""
for char in data:
encoded_data += huffman_code[char]
return encoded_data, huffman_code
print(huffman_encoding("aaaaabbbcccc"))
6.分治法:
归并排序:上面已经解释过了
7.回溯:
The N-Queens Problem:这是一个可以使用回溯法解决的经典问题。目标是将 N 个问题放在 NxN 的棋盘上,使得任何皇后都不能攻击任何其他皇后。
def solveNQueens(n):
def could_place(row, col):
# check if a queen can be placed on board[row][col]
# check if this row is not under attack from any previous queen in that column
for i in range(row):
if board[i] == col or abs(board[i] - col) == abs(i - row):
return False
return True
def backtrack(row=0, count=0):
for col in range(n):
if could_place(row, col):
board[row] = col
if row + 1 == n:
count += 1
else:
count = backtrack(row + 1, count)
return count
board = [-1 for x in range(n)]
return backtrack()
print(solveNQueens(4))
该算法开始将皇后放置在第一行,并且对于每个放置的皇后,它检查它是否受到任何先前皇后的攻击。
如果不是,它将继续到下一行并重复该过程。如果将皇后置于受到攻击的位置,算法会回溯并尝试不同的位置。这一直持续到所有皇后都被放置在棋盘上且没有任何相互攻击。
8.随机算法:
随机快速排序:随机选择主元的快速排序算法的一种变体。
import random
def randomized_quicksort(arr):
if len(arr) <= 1:
return arr
pivot = random.choice(arr)
left = [x for x in arr if x < pivot]
middle = [x for x in arr if x == pivot]
right = [x for x in arr if x > pivot]
return randomized_quicksort(left) + middle + randomized_quicksort(right)
print(randomized_quicksort([3,6,8,10,1,2,1]))
这些是每个程序员都应该熟悉的一些最常用的算法。了解这些算法与它的实现可以帮助程序员在设计和实现高效解决方案时做出更好的决策。
每个程序员都应该知道的最强大的 Unix 命令或脚本示例
【中文标题】每个程序员都应该知道的最强大的 Unix 命令或脚本示例【英文标题】:Most powerful examples of Unix commands or scripts every programmer should know 【发布时间】:2010-11-09 08:00:36 【问题描述】:有很多事情是所有程序员都应该知道的,但我对我们都应该知道的 Unix/Linux 命令特别感兴趣。用于完成我们在某些时候可能会遇到的任务,例如重构、报告、网络更新等。
之所以好奇,是因为我在攻读学位期间曾在一家软件公司担任软件测试员,我注意到所有开发人员(开发 Windows 软件)都有两台电脑。
他们的左边是他们的 Windows XP 开发机器,右边是 Linux 机器。我认为是 Ubuntu。无论如何,他们告诉我他们之所以使用它,是因为它提供了 Windows 在他们的开发过程中无法做到的强大的 unix 操作。
这让我很想知道,作为一名软件工程师,您认为哪些是您可以在 Unix/Linux 操作系统上执行的最强大的脚本/命令/用途,每个程序员都应该知道这些脚本/命令/用途是为了解决现实世界的任务这可能不一定与编写代码有关?
我们都知道 sed、awk 和 grep 的作用。我对一些实际的 Unix/Linux 脚本片段感兴趣,它们已经为您解决了一个难题,因此其他程序员可能会受益。请提供您的故事和来源。
我相信人们在他们的“Scripts”文件夹中保存了许多这样的示例。
更新:人们似乎误解了这个问题。我不是在询问单个 unix 命令的名称,而是为您解决了问题的 UNIX 代码 sn-ps。
来自社区的最佳答案
遍历目录树并打印出任何与正则表达式匹配的文件的路径:
find . -exec grep -l -e 'myregex' \; >> outfile.txt
调用默认编辑器(Nano/ViM)
(适用于大多数 Unix 系统,包括 Mac OS X) 默认编辑器是您的任何 “EDITOR”环境变量是 调成。即:出口 EDITOR=/usr/bin/pico 这是 位于 Mac OS 下的 ~/.profile 十。
Ctrl+x Ctrl+e
列出所有正在运行的网络连接(包括它们所属的应用)
lsof -i -nP
清除终端的搜索历史(我最喜欢的另一个)
history -c
【问题讨论】:
如果这是一个社区 wiki 会更好(我认为)。 好的,它现在是一个社区维基 有趣的是 Ctrl-x Ctrl-e,但在我的例子中它调用了 Vim...xD 它调用任何设置的“EDITOR”环境变量。 【参考方案1】:你的 shell 是你可用的最强大的工具
-
能够编写简单的循环等
了解文件通配(例如 *.java 等)
能够通过管道、子shell 将命令放在一起。重定向等。
拥有该级别的 shell 知识允许您在命令行上执行大量操作,而无需通过临时文本文件、复制/粘贴等记录信息,并利用大量允许切片/数据切块。
Unix Power Tools 将向您展示这么多。每次打开我的副本,我都会发现一些新东西。
【讨论】:
【参考方案2】: grep awk sed perl 找到Unix 的强大功能来自于它处理文本文件和过滤数据的能力。当然,您可以获得所有这些适用于 Windows 的命令。它们只是在操作系统中不是原生的,就像在 Unix 中一样。
以及将命令与管道等链接在一起的能力。这可以从简单的函数创建极其强大的单行命令。
【讨论】:
实际上,它们往往是 shell 原生的,而不是 OS 如果您安装适用于 Windows 的 Unix 子系统(也称为适用于 Unix 的 Windows 服务),它们在技术上是 Windows 原生的。它是一个完整的本机子系统,如 Win32,并排运行。只是为了记录。另一方面,如果你说的是原生并且真正的意思是“不会让用户感到陌生”,那么你是对的 ;) Xetius 提到的所有程序都不是 shell ZombieSheep 的原生程序【参考方案3】:Grep(试试Windows Grep)
sed(试试Sed for Windows)
事实上,http://gnuwin32.sourceforge.net/ 提供了大量非常有用的 *nix 命令端口。如果你有 *nix 背景并且现在使用 windows,你应该检查一下。
【讨论】:
Windows 有一个极其简化的 grep,名为findstr
。如果您只需要在不使用正则表达式的情况下在某些输出中查找字符串,则可以省去安装第三方软件的麻烦。当然,Grep 仍然更胜一筹。【参考方案4】:
在解决有故障的 linux 机器上的问题时,到目前为止,我输入的最常见的键序列最终输入是 alt+sysrq R E I S U B
【讨论】:
【参考方案5】:你可以用这个做任何事情......
海合会
【讨论】:
我问的不是编译语言,而是实际的 UNIX 代码 sn-ps【参考方案6】:如果你随身携带一份备忘单会更好......没有一个命令可以被称为最有用的。如果一个特定的命令能完成你的工作,它是有用且强大的
编辑您想要强大的 shell 脚本吗? shell 脚本是程序。掌握正确的基础知识,建立在单独的命令上,您将获得所谓的强大脚本。满足您需求的功能强大,否则无用。如果你提到一个问题并询问如何解决它会更好。
【讨论】:
什么对您有用?提供它的使用示例和来源。【参考方案7】:这些工具(grep find、awk、sed)的强大之处在于它们的多功能性,因此给出一个特定的案例似乎毫无用处。
man 是最强大的命令,因为这样您就可以理解您键入的内容,而不是盲目地从堆栈溢出中复制粘贴。
欢迎提供示例,但已经有针对 tis 的主题。 我最常用的:
grep something_to_find * -R
可以用ack和替换
find | xargs
将结果通过管道传输到 xargs 的查找功能非常强大
【讨论】:
man 是一个奇怪的例子,因为力量来自于阅读文档,而 man 只是一个展示文档的工具。这就像说 Document Explorer 是使用 Visual Studio 开发时最强大的工具,因为它显示了文档。 我的意思是在网页上尽可能多地插入单行代码并不是很有用。人们应该明白他们在做什么【参考方案8】:我发现 commandlinefu.com 是各种 shell 脚本配方的绝佳资源。
示例
常见
# Run the last command as root
sudo !!
# Rapidly invoke an editor to write a long, complex, or tricky command
ctrl-x ctrl-e
# Execute a command at a given time
echo "ls -l" | at midnight
深奥
# output your microphone to a remote computer's speaker
dd if=/dev/dsp | ssh -c arcfour -C username@host dd of=/dev/dsp
【讨论】:
整个网站 (commandlinefu.com) 是对 OP 问题的回答。 酷!一年前我发现了这个网站,但忘了给它加书签。谢谢你把它还给我:-) +1 我第一次听说 Ctrl-x Ctrl-e ,我认为这是一个 bash 的事情。无论 EDITOR 设置为什么,它都会尝试执行我没有的 emacs - 如何更改它? noselasd: 不是叫 /usr/bin/editor 吗? (这是我 Ubuntu 中 /etc/alternatives/editor 的符号链接)【参考方案9】:顺便说一句,但你可以在 Windows 上获得 powershell。它真的很强大,可以做很多 *nix 类型的东西。一个很酷的区别是您使用 .net 对象而不是文本,如果您使用管道进行过滤等,这可能很有用。
或者,如果您不需要 .NET 集成,请在 Windows 框中安装 Cygwin。 (并将其目录添加到 Windows PATH。)
【讨论】:
【参考方案10】:你们中的一些人可能不同意我的观点,但是,这里有一些事情要谈。如果一个人彻底学习 gawk(其他变体),则可以跳过学习并使用 grep/sed/wc/cut/paste 和其他一些 *nix 工具。你所需要的只是一个很好的工具来完成许多组合的工作。
【讨论】:
反面怎么样?我学习了其他工具,所以我可以跳过学习 awk 吗? 1) 将太多工具链接在一起会增加开销。他们的大部分功能也重叠 2)你减少了你的学习曲线。 3)有些人可能会说,那为什么不学习 Perl/Python 等,因为他们可以做同样的事情,甚至更多。【参考方案11】:某种搜索(多个)格式错误的日志文件的方法,其中搜索字符串可能会在“孤立”的下一行中找到。例如,要在搜索 id = 110375 时同时显示第 1 行以及连接的第 3 行和第 4 行:
[2008-11-08 07:07:01] [INFO] ...; id = 110375; ...
[2008-11-08 07:07:02] [INFO] ...; id = 238998; ...
[2008-11-08 07:07:03] [ERROR] ... caught exception
...; id = 110375; ...
[2008-11-08 07:07:05] [INFO] ...; id = 800612; ...
我想在实际运行grep
之前,肯定有比使用sed
将两行连接起来更好的解决方案(是的,添加它们...!):
#!/bin/bash
if [ $# -ne 1 ]
then
echo "Usage: `basename $0` id"
echo "Searches all myproject's logs for the given id"
exit -1
fi
# When finding "caught exception" then append the next line into the pattern
# space bij using "N", and next replace the newline with a colon and a space
# to ensure a single line starting with a timestamp, to allow for sorting
# the output of multiple files:
ls -rt /var/www/rails/myproject/shared/log/production.* \
| xargs cat | sed '/caught exception$/N;s/\n/: /g' \
| grep "id = $1" | sort
...屈服:
[2008-11-08 07:07:01] [INFO] ...; id = 110375; ...
[2008-11-08 07:07:03] [ERROR] ... caught exception: ...; id = 110375; ...
实际上,更通用的解决方案是将所有(可能是多个)不以某个 [timestamp] 开头的行附加到其前一行。任何人?当然,不一定要使用sed
。
【讨论】:
【参考方案12】:for card in `seq 1 8` ;do
for ts in `seq 1 31` ; do
echo $card $ts >>/etc/tuni.cfg;
done
done
比手动编写愚蠢的 248 行配置要好。
需要删除一些以 'tmp' 为前缀的剩余表
for table in `echo show tables | mysql quotiadb |grep ^tmp` ; do
echo drop table $table
done
查看输出,重新运行循环并将其通过管道传输到 mysql
【讨论】:
如果使用 bash,而不是使用外部 seq 命令,使用 1..8 , 1..31 seq 是一个非常强大的结构【参考方案13】:我个人最喜欢的是 lsof 命令。
"lsof" 可用于列出打开的文件描述符、套接字和管道。 当我试图找出哪些进程使用了我机器上的哪些端口/文件时,我发现它非常有用。
示例:列出所有没有主机名解析且没有端口到端口名称转换的 Internet 连接。
lsof -i -nP
http://www.manpagez.com/man/8/lsof/
【讨论】:
【参考方案14】:如果您在长命令中打错字,您可以使用替换(在 bash 中)重新运行该命令:
mkdir ~/aewseomeDirectory
您可以看到“awesome”拼写错误,您可以键入以下内容重新运行命令并纠正错字
^aew^awe
然后它输出它替换的内容 (mkdir ~/aweseomeDirectory
) 并运行命令。 (不要忘记撤消您使用错误命令造成的损坏!)
【讨论】:
非常有用。到目前为止,我只使用过!!
,但是 bash 有很多非常方便的方法可以重复你做错的事情,但会稍作改动。【参考方案15】:
我经常使用它,我真的为自己感到羞耻。从所有文件名中删除空格并用下划线替换它们:
[removespaces.sh]
#!/bin/bash
find . -type f -name "* *" | while read file
do
mv "$file" "$file// /_"
done
【讨论】:
我知道反转(将下划线转换为空格)很容易转换回来,也许您可以将其作为第二个脚本添加到您的答案中【参考方案16】:在不显示 grep 本身的情况下查找 PID
export CUPSPID=`ps -ef | grep cups | grep -v grep | awk 'print $2;'`
【讨论】:
您可以仅使用 awk 来缩短链接数量:ps -ef|awk '/cups/&&!/awk/print $2'【参考方案17】:您可以在 find 命令中多次使用 -name 和 -iname 的事实让我大开眼界。
[findplaysong.sh]
#!/bin/bash
cd ~
echo Matched...
find /home/musicuser/Music/ -type f -iname "*$1*" -iname "*$2*" -exec echo \;
echo Sleeping 5 seconds
sleep 5
find /home/musicuser/Music/ -type f -iname "*$1*" -iname "*$2*" -exec mplayer \;
exit
【讨论】:
【参考方案18】:当事情在一台服务器上运行但在另一台服务器上出现故障时,您可以比较所有相关库:
export MYLIST=`ldd amule | awk ' print $3; '`; for a in $MYLIST; do cksum $a; done
将此列表与机器之间的列表进行比较,您可以快速找出差异。
【讨论】:
【参考方案19】:如何退出VI
:wq
保存文件并结束痛苦。
“:wq
”的替代品是“:x
”以保存并关闭 vi 编辑器。
【讨论】:
是的,结束痛苦!我讨厌 vi! 当你不记得 :wq 时,ZZ 也会做同样的事情。 (顺便说一句,使用 vi 仅在最初的 2-3 年内会很痛苦,然后你的大脑会越过,之后,使用其他任何东西都会很痛苦;))【参考方案20】:tr 命令是 Unix 中最被低估的命令:
#Convert all input to upper case
ls | tr a-z A-Z
#take the output and put into a single line
ls | tr "\n" " "
#get rid of all numbers
ls -lt | tr -d 0-9
【讨论】:
【参考方案21】:在不使机器过载过多的情况下并行运行多个进程(在多处理器架构中):
NP=`cat /proc/cpuinfo | grep processor | wc -l`
#your loop here
if [ `jobs | wc -l` -gt $NP ];
then
wait
fi
launch_your_task_in_background&
#finish your loop here
【讨论】:
你可能会失去猫。 grep 处理器 /proc/cpuinfo | wc -l 是的,这只是一个坏习惯...... ^_^ 我发现在使用管道时将输入分开而不是使用文件参数更清楚;因此,如果我必须将参数更改为“grep”(或其他),则文件名不会乱七八糟。【参考方案22】:来自社区的最佳答案
遍历目录树并打印出任何与正则表达式匹配的文件的路径:
find . -exec grep -l -e 'myregex' \; >> outfile.txt
调用默认编辑器(Nano/ViM)
(适用于大多数 Unix 系统,包括 Mac OS X) 默认编辑器是您的任何 “EDITOR”环境变量是 调成。即:出口 EDITOR=/usr/bin/pico 这是 位于 Mac OS 下的 ~/.profile 十。
Ctrl+x Ctrl+e
列出所有正在运行的网络连接(包括它们所属的应用)
lsof -i -nP
清除终端的搜索历史(我最喜欢的另一个)
history -c
【讨论】:
【参考方案23】:启动所有网络服务
find -iname '*weservice*'|xargs -I service restart
在 java 子目录中搜索本地类
find -iname '*.java'|xargs grep 'class Pool'
在当前路径的子目录中递归查找文件中的所有项目:
cat searches.txt| xargs -I -d, -n 1 grep -r
P.S search.txt: first,second,third, ... ,million
【讨论】:
【参考方案24】::() :|: & ;:
Fork Bomb 没有 root 访问权限。
请自行承担风险。
【讨论】:
【参考方案25】:在 bash 中使用 !!
重复您之前的命令。我经常运行chown otheruser: -R /home/otheruser
却忘记使用 sudo。如果您忘记了 sudo,请使用 !!比向上箭头然后回家要容易一些。
sudo !!
我也不喜欢自动解析的主机名和端口名称,所以我保留了一个映射到iptables -nL --line-numbers
的 iptables 别名。我什至不确定为什么默认隐藏行号。
最后,如果你想检查一个进程是否正在监听一个端口,绑定到你可以运行的正确地址
netstat -nlp
然后你可以 grep 进程名或端口号(-n 给你数字)。
我也喜欢在终端中使用颜色。我喜欢将它添加到我的 bashrc 中,以提醒我是否是 root,甚至无需阅读它。这实际上帮助了我很多,我再也不会忘记 sudo 了。
red='\033[1;31m'
green='\033[1;32m'
none='\033[0m'
if [ $(id -u) -eq 0 ];
then
PS1="[\[$red\]\u\[$none\]@\H \w]$ "
else
PS1="[\[$green\]\u\[$none\]@\H \w]$ "
fi
这些都是非常简单的命令,但我经常使用它们。他们中的大多数甚至应该在我的机器上使用别名。
【讨论】:
以上是关于每个程序员都应该知道的8大算法的主要内容,如果未能解决你的问题,请参考以下文章