前缀、中缀、后缀表达式

举例:

(3 + 4) × 5 - 6 就是中缀表达式
- × + 3 4 5 6 前缀表达式
3 4 + 5 × 6 - 后缀表达式

栗子:

中缀表达式 a+bc-(d+e) 转化为前缀 与 后缀
第一步:按照运算符的优先级对所有的运算单位加括号~
式子变成拉:((a+(b
c))-(d+e))
第二步:转换前缀与后缀表达式
前缀:把运算符号移动到对应的括号前面
则变成拉:-( +(a (bc)) +(de))
把括号去掉:-+a
bc+de 前缀式子出现
后缀:把运算符号移动到对应的括号后面
则变成拉:((a(bc) )+ (de)+ )-
把括号去掉:abc
+de+- 后缀式子出现

习题:

某表达式的前缀形式为”+-*^ABCD/E/F+GH”,它的中缀形式为()

从右至左扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈;重复上述过程直到表达式最左端,最后运算得出的值即为表达式的结果。
根据从右至左扫描计算过程如下:

题目中的前缀形式为:+-^ABCD/E/F+GH
1) 首先扫描 H,是数字 入栈 ,栈中为: H
2) 扫描 G 为数字 入栈 ,栈中为:G,H
3)扫描+ 为运算符 ,依次弹出G ,H ,得到 G+H 的结果 入栈,栈中为: G+H(在这里方便讲解 标记为 G+H)
4)扫描 F 为数字 ,入栈 ,栈中为 F, G+H
5)扫描 / 为运算符, 依次弹出 F,G+H ,计算F/(G+H) 的结果入栈 ,栈中为 F/(G+H)
6)扫描 E 为数字,入栈,栈中为 E, F/(G+H)
7) 扫描 / 为运算符, 依次弹出E, F/(G+H) ,计算 E/(F/(G+H))
8)扫描 D 为数字,入栈 栈中为:D, E/(F/(G+H))
9) 扫描 C 为数字,入栈 栈中为:C,D, E/(F/(G+H))
10) 扫描 B 为数字,入栈 栈中为:B,C,D, E/(F/(G+H))
11) 扫描 A 为数字,入栈 栈中为:A,B,C,D, E/(F/(G+H))
12) 扫描^ 为数字,依次弹出 A,B 计算 A^B的结果入栈, 栈中为:A^B ,C,D, E/(F/(G+H))
13) 扫描
为数字,依次弹出 A^B,C 计算 A^BC的结果入栈, 栈中为:A^B C,D, E/(F/(G+H))
14) 扫描-为数字,依次弹出 A^BC,D 计算 A^BC-D的结果入栈, 栈中为:A^B C-D, E/(F/(G+H))
15) 扫描+为数字,依次弹出 A^B
C-D, E/(F/(G+H)) 计算 A^BC-D+ E/(F/(G+H)) 的到结果
最后得到的表达式为: A^B
C-D+ E/(F/(G+H))

每天一道编程题——洗牌

洗牌在生活中十分常见,现在需要写一个程序模拟洗牌的过程。 现在需要洗2n张牌,从上到下依次是第1张,第2张,第3张一直到第2n张。首先,我们把这2n张牌分成两堆,左手拿着第1张到第n张(上半堆),右手拿着第n+1张到第2n张(下半堆)。接着就开始洗牌的过程,先放下右手的最后一张牌,再放下左手的最后一张牌,接着放下右手的倒数第二张牌,再放下左手的倒数第二张牌,直到最后放下左手的第一张牌。接着把牌合并起来就可以了。 例如有6张牌,最开始牌的序列是1,2,3,4,5,6。首先分成两组,左手拿着1,2,3;右手拿着4,5,6。在洗牌过程中按顺序放下了6,3,5,2,4,1。把这六张牌再次合成一组牌之后,我们按照从上往下的顺序看这组牌,就变成了序列1,4,2,5,3,6。 现在给出一个原始牌组,请输出这副牌洗牌k次之后从上往下的序列。

输入描述:
第一行一个数T(T ≤ 100),表示数据组数。对于每组数据,第一行两个数n,k(1 ≤ n,k ≤ 100),接下来一行有2n个数a1,a2,…,a2n(1 ≤ ai ≤ 1000000000)。表示原始牌组从上到下的序列。
输出描述:
对于每组数据,输出一行,最终的序列。数字之间用空格隔开,不要在行末输出多余的空格。

输入例子:
3
3 1
1 2 3 4 5 6
3 2
1 2 3 4 5 6
2 2
1 1 1 1
输出例子:
1 4 2 5 3 6
1 5 4 3 2 6
1 1 1 1


1
2
3
4
5
6
7
8
9
10
11
def wash_card(card_list, repeat, length):
if repeat < 1:
return card_list
left = card_list[:length]
right = card_list[length:]
new_card_list = []
for i in range(length - 1, -1, -1):
new_card_list.append(right[i])
new_card_list.append(left[i])
new_card_list.reverse()
return wash_card(new_card_list, repeat - 1, length)

来自 网易有道2017内推编程题

Django获取用户IP地址

前言

经过反向代理后,由于在客户端和Web服务器之间增加了中间层,因此Web服务器无法直接拿到客户端的IP。
由于使用反向代理的缘故,Django中HttpRequest.META[‘REMOTE_ADDR’]是得到localhost的地址。

X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是client1, proxy1, proxy2,以逗号隔开各个地址,由于他是非rfc标准,所以默认是没有的,需要强制添加,在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip 。

步骤

在Nginx配置文件中的server里加入

1
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

然后再Django中访问HttpRequest的META[‘HTTP_X_FORWARDED_FOR’]就可以得到正确的IP地址。

Linux设置iptables防火墙


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//建议设置的时候快照一下,万一22端口莫名被墙就惨了
//推荐设置
iptables -L //查看规则
iptables -D INPUT 4 //删除一条规则,例如第4行规则
iptables -F //清空所有规矩
iptables -A INPUT -s 127.0.0.1 -j ACCEPT //允许本机内部所有网络通信
iptables -A INPUT -p tcp --dport 22 -j ACCEPT //开放22端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 25 -j ACCEPT
iptables -A INPUT -p tcp --dport 465 -j ACCEPT
iptables -A INPUT -p tcp --dport 110 -j ACCEPT
iptables -A INPUT -p tcp --dport 995 -j ACCEPT
iptables -A INPUT -p tcp --dport 143 -j ACCEPT
iptables -A INPUT -p tcp --dport 993 -j ACCEPT
iptables -A INPUT -p tcp --dport 20 -j ACCEPT
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
//-A(–append):该命令会把一条规则附件到chain的末尾。
//-D(–delete)用来删除某个规则。
//-F(–flush)如果指定了chain,删除该chain中的所有规则,如果未指定chain,则删除所有chain中的所有规则。
iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT //允许所有从服务器端发起的连接返回的数据
//默认规则
iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP
service iptables save //保存规矩
service iptables restart
//其他设置
iptables -A -p udp -j DROP //禁止所有udp端口
iptables -A INPUT -s 192.168.1.0/24 -j DROP //禁止ip段

《Merry Christmas Mr. Lawrence》


多媒体老师点名,一个班只来了不到十个人,确实有点寒酸。该实习的去实习,该找工作的去找工作,剩下像我这样无所事事到来上课的已没几个人了。

本来眼看初秋将至,何奈最近两天的气温清楚地告诉我这是一种错觉。每年都是如此,反反复复来来回回。

校园处处可见新生的身影,校园各地洋溢着欢乐祥和的气息——就像三年之前一样。记得我三年前曾在一篇文章里说到,“九月,是起点,更是终点。”四年的大学生活,感觉三年便已经过完了。

最近脑里总是单曲循环这首歌。

星座跟我一样的坂田龙一,是我挺喜欢的一个日本艺人。说艺人其实也说不上了,他出演的都是不起眼的小角色,《Merry Christmas Mr. Lawrence 》里的日军营长,《The Last Emperor》里的甘粕正彦满映理事长。他给别人留下深刻影响大概都是因为那些深刻的电影配乐。

日本的很多音乐似乎都透着一种压抑,一种隐隐约约的压抑。亦或并非如此,实是言者无心,听者有意罢了。

八大排序算法及其性能(Python实现)










1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import time
import random
import copy
def bubble_sort(list):
'''
冒泡排序
'''
length = len(list)
# 第一级遍历
for index in range(1, length):
# 第二级遍历
for j in range(1, length - index):
if list[j] > list[j + 1]:
# 交换两者数据,这里没用temp是因为python 特性元组。
list[j + 1], list[j] = list[j], list[j + 1]
return list
def bubble_sort_flag(list):
'''
带标记的冒泡排序
'''
length = len(list)
flag = True
for index in range(1, length):
if not flag: # 没有发生交换,直接返回list
return list
flag = False
for j in range(1, length - index):
if list[j] > list[j + 1]:
list[j + 1], list[j] = list[j], list[j + 1]
flag = True
return list
def selection_sort(list):
'''
选择排序
'''
n = len(list)
for i in range(1, n):
min = i
for j in range(i + 1, n):
if list[j] < list[min]:
min = j
if i != min:
list[min], list[i] = list[i], list[min]
return list
def insert_sort(list):
'''
插入排序
'''
n = len(list)
for i in range(2, n):
# 后一个元素和前一个元素比较
# 如果比前一个小
if list[i] < list[i - 1]:
list[0] = list[i]
j = i - 1
while list[j] > list[0]:
list[j + 1] = list[j]
j -= 1
list[j + 1] = list[0]
return list
def shell_sort(list):
'''
希尔排序
'''
length = len(list)
# 初始步长
increment = length
while increment > 1:
increment = increment // 3 + 1;
for i in range(increment + 1, length):
if list[i] < list[i - increment]:
list[0] = list[i]
j = i
while j >= increment and list[j - increment] > list[0]:
list[j] = list[j - increment]
j -= increment
list[j] = list[0]
return list
def merge_sort(list):
'''
归并排序
'''
# 认为长度不大于1的数列是有序的
if len(list) <= 1:
return list
# 二分列表
middle = len(list) // 2
left = merge_sort(list[:middle])
right = merge_sort(list[middle:])
# 最后一次合并
return merge(left, right)
# 合并
def merge(left, right):
l, r = 0, 0
result = []
while l < len(left) and r < len(right):
if left[l] < right[r]:
result.append(left[l])
l += 1
else:
result.append(right[r])
r += 1
result += left[l:]
result += right[r:]
return result
def quick_sort(list):
'''
快速排序
'''
if len(list) <= 1:
return list
else:
pivot = list[0]
return quick_sort([x for x in list[1:] if x < pivot]) + [pivot] + quick_sort([x for x in list[1:] if x >= pivot])
def shiftDown(arr, index, length): # 自顶向下堆化,从k开始堆化
N = length - 1
while 2 * index <= N:
j = 2 * index
if j < N and arr[j] < arr[j + 1]: # 选出左右孩子节点中更大的那个
j += 1
if arr[index] < arr[j]:
arr[index], arr[j] = arr[j], arr[index]
index = j
else:
break
def heap_Sort(l):
'''
堆排序
'''
n = len(l) - 1
for i in range(n // 2, 0, -1):
shiftDown(l, i, len(l))
while n > 1:
l[1], l[n] = l[n], l[1]
shiftDown(l, 1, n)
n -= 1
def count_sort(list):
'''
计数排序
'''
# 取得最大值和最小值
max_ = max(list)
min_ = min(list)
# 创建数组C
length = max_ - min_ + 1
count = [0] * length
# 统计每项出现的次数
for index in list:
if index > 0:
count[index] += 1
# 负数放在最大数后面
if index < 0:
count[max_ + abs(index)] += 1
index = 1
# 填值
for a in range(length - 1, max_, -1):
for c in range(1, count[a] + 1):
list[index] = -a + max_
index += 1
for a in range(max_ + 1):
for c in range(1, count[a] + 1):
list[index] = a
index += 1
return list
def test(func, random_list):
l = copy.deepcopy(random_list)
print(func.__doc__)
s = time.time()
func(l)
print(time.time() - s)
func = [bubble_sort, bubble_sort_flag, selection_sort, insert_sort, merge_sort, shell_sort, quick_sort, count_sort,
heap_Sort]
for i in range(3):
print('-----------------')
random_list = [random.randint(1, 10000) for i in range(40)]
random_list[0] = 0
last = []
for each_func in func:
test(each_func, random_list)

顺序表的几种查找

顺序查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int Sequential_search(int* a,int n,int key)
{
int i;
for (i = 1; i <=n; i++)
{
if(a[i]==key)
return i;
}
return 0;
}
// 有哨兵版
// 时间复杂度O(n)
int Sequential_search(int* a,int n,int key)
{
int i;
a[0]=key;
i=n;
while(a[i]!=key)
i--;
return i;
}

折半查找(二分查找)

二分检索算法的每一步,搜索空间总会减半,因此保证了运行时间。在数组中查找一个特定元素,可以保证在 O(log(n))时间内完成,而且如果找的正好是中间元素就更快了。也就是说,要从81,920,000个元素的数组中找某个元素的位置,只需要27个甚至更少的迭代。
由于二分检索的随机跳跃性,该算法并非缓存友好的,因此只要搜索空间小于特定值(64或者更少),一些微调的二分检索算法就会切换回线性检索继续查找。然而,这个最终的空间值是极其架构相关的,因此大部分框架都没有做这个优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 时间复杂度O(logn)
int Binary_Search(int* a,int n,int key)
{
int low,high,mid;
low=1;
high=n;
while(low<=high)
{
mid=(low+high)/2; //折半
if(a[mid]>key)
high=mid-1;
else if(a[mid]<key)
low=mid+1;
else //a[mid]==key
return mid;
}
return 0;
}

插值查找

类似于人类使用电话簿的方法,它试图通过假设元素在数组中均匀分布,来猜测元素的位置。
首先,它抽样选择出搜索空间的开头和结尾,然后猜测元素的位置。算法一直重复这个步骤,直到找到元素。如果猜测是准确的,比较的次数大概是O(log(log(n)),运行时间大概是O(log(n));但如果猜测的不对,运行时间就会是O(n)了。
对于分布比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好得多




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 插值查找
int Insert_Search(int* a,int n,int key)
{
int low,high,mid;
low=1;
high=n;
while(low<=high)
{
mid=low+(high-low)*(key-a[low])/(a[high]-a[low]); //插值
if(a[mid]>key)
high=mid-1;
else if(a[mid]<key)
low=mid+1;
else //a[mid]==key
return mid;
}
return 0;
}


# 斐波那契查找
在数学上,斐波那契被递归方法如下定义:F(1)=1,F(2)=1,F(n)=f(n-1)+F(n-2) (n>=2)。该数列越往后相邻的两个数的比值越趋向于黄金比例值(0.618)。
波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。
斐波那契查找的时间复杂度还是O(log2n),但是 与折半查找相比,斐波那契查找的优点是它只涉及加法和减法运算,而不用除法,而除法比加减法要占用更多的时间,因此,斐波那契查找的运行时间理论上比折半查找小,但是还是得视具体情况而定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 斐波那契查找
// 斐波那契数列:
// 0 1 2 3 4 5 6 ....
// 0 1 1 2 3 5 8 ....
int Fibonacci_Search(int* a,int n,int key)
{
int low,hgih,mid,i,k;
low=1;
high=n;
k=0;
while(n<F[k]-1) //计算n位于斐波那契数列的位置
k++;
for(i=n;i<F[k]-1;i++) //对不满的数值补全,防止数组越界
a[i]=a[n];
while(low<=high)
{
mid=low+F[k-1]-1;
if(a[mid]>key)
{
high=mid-1;
k=k-1;
}
else if(a[mid]<key)
{
low=mid+1;
k=k-2;
}
else
{
if(mid<n)
return mid;
else
return n; //mid>n说明是最后一个,返回n
}
}
return 0;
}


要点:
1. 当key=a[mid]时,查找成功
2. 当keya[mid]时,新范围是第mid+1个到第high个,此时范围个数为F[k-2]-1个


Vim 操作集合

打开文件

vim 打开 Vim 欢迎页面
vim filename 打开文件,文件名不存在是创建文件
vim foldername 打开文件夹
:open file 当前窗口打开文件
:split file 新窗口打开文件
:bn 下一个文件
:bp 上一个文件

模式切换

正常模式(按Esc或Ctrl+[进入) 左下角显示文件名或为空
插入模式(按i键进入) 左下角显示–INSERT–
可视模式(按v进入) 左下角显示–VISUAL–

插入命令

i 在当前位置生前插入
I 在当前行首插入
a 在当前位置后插入
A 在当前行尾插入
o 在当前行之后插入一行
O 在当前行之前插入一行

查找命令

/text  查找text,按n健查找下一个,按N健查找前一个。
?text  查找text,反向查找,按n健查找下一个,按N健查找前一个。
光标移动到该词上,按或#键即可以该单词进行搜索,相当于/搜索。而#命令相当于?搜索
vim中有一些特殊字符转义  .
[]^%/?~$

替换命令

s/old/new/ old替换new,替换当前行的第一个匹配
s/old/new/g old替换new,替换当前行的所有匹配
%s/old/new/ old替换new,替换所有行的第一个匹配
%s/old/new/g old替换new,替换整个文件的所有匹配

移动命令

h 左移一个字符
l 右移一个字符
k 上移一个字符
j 下移一个字符
以上命令可以与数字组合,如先按2再按j就是向下移动两个字符
w 向前移动一个单词,光标停留在行首,如果已到行尾,则转至下一行行首。
b 向后移动一个单词
e 同w,光标停在单词尾部
ge 同b,光标停在单词尾部
gg 移动到文件头
G 移动到文件尾
^ 移动到本行第一个非空白字符上
0 移动到本行第一个字符上
:200 跳转到行数
Ctrl + e 向下滚动一行
Ctrl + y 向上滚动一行
Ctrl + d 向下滚动半屏
Ctrl + u 向上滚动半屏
Ctrl + f 向下滚动一屏
Ctrl + b 向上滚动一屏

撤销操作

u 撤销(Undo)
U 撤销对整行的操作
Ctrl + r 重做,相当于 Windows 里用的 Ctrl Y

删除操作

x 删除光标后字符
3x 删除当前光标开始向后三个字符
X 删除当前字符的前一个字符
dd 删除当前行
10d 删除当前行开始的10行。
D 删除当前字符至行尾
:1,10d 删除1-10行

复制粘贴剪切

进入可视模式,hljk移动光标,选中部分高亮

y 复制高亮部分
d 剪切

普通模式

yy 拷贝当前行
nyy 拷贝当前后开始的n行
p 在当前光标后粘贴
P 在当前行前粘贴
ddp 交换当前行和其下一行
xp 交换当前字符和其后一个字符

全局命令

:wq 保存并退出
:q! 强制退出并忽略所有更改
:e! 放弃所有修改,并打开原来文件
Ctrl+ww 移动到下一个窗口
Ctrl+wj 移动到下方的窗口
Ctrl+wk 移动到上方的窗口
:close 最后一个窗口不能使用此命令

注释命令

1,10 s/^/#/g 注释第1-10行
1,10 s/^#//g 解除1-10行的注释

执行

:!command 执行shell命令

其他

:help xxx 显示xxx的帮助,比如 :help i, :help CTRL-[(即Ctrl+[的帮助)。
:help ‘number’ Vim选项的帮助用单引号括起
:help 特殊键的帮助用<>扩起


转自:AppleHater

《什么值得买》的推送服务

前言:

什么值得买是一个很好玩的网站,但是因为用的人多,其优惠信息发布不久便已经失效。作者编写这个软件就是为了能及时将自己感兴趣的商品推送至微信。

其实什么值得买app也有推送功能,不过在iOS上面,其推送功能似乎有点问题(亦或是作者手机的问题?)。而且其推送功能限制较多,比如不能根据评论数量推送,不能根据商品价格推送。

这个推送服务,可以根据您自己的需要添加以下一条或多条过滤条件

  • 根据标题过滤(关键词)
  • 根据评论数量过滤(大于)
  • 根据分类过滤(关键词)
  • 根据商城过滤(关键词)
  • 根据价格过滤(大于)
  • 根据价格过滤(小于)
  • 根据值过滤(大于)
  • 根据不值过滤(小于)
  • 根据值的百分比过滤(大于)
  • 根据收藏数量过滤(大于)
  • 根据价格过滤(关键词)

效果:

在微信端显示效果






网页端显示效果



开始推送

注册

现在只支持QQ邮箱注册,用户名就是您的QQ号码。




注册完成后,进到您的邮箱里面验证。注意:可能本邮件会被标识为垃圾邮件。请仔细查找。



添加推送




您可以添加多条过滤条件
-(关键词):表示可以是数字或文字
-(大于),(小于):只能为数字

  • 根据标题过滤(关键词)
  • 根据评论数量过滤(大于)
  • 根据分类过滤(关键词)
  • 根据商城过滤(关键词)
  • 根据价格过滤(大于)
  • 根据价格过滤(小于)
  • 根据值过滤(大于)
  • 根据不值过滤(小于)
  • 根据值的百分比过滤(大于)
  • 根据收藏数量过滤(大于)
  • 根据价格过滤(关键词)

比如,我需要:阿迪达斯牌子的大于200元的在京东买的商品。您可以这样添加。




您可以添加任意多条推送




最后,在您的微信——我——设置——通用——功能——QQ邮箱提醒 ,打开邮箱提醒,就能在微信接受到推送了。
直达链接

|