Categories
不学无术 木有技术

浅谈PCA 人脸识别

版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://leen2010.blogbus.com/logs/124631640.html

前几天讨论班我讲了基于PCA的人脸识别,当时我自己其实也只是知道这个算法流程,然后基于该算法利用c++实现了,效果还不错。后来跟师兄一起讨论的时候,才发现这个PCA还是有相当深刻的意义。
PCA的算法:矩阵C=AAT,A的每一列是一张人脸(将一张人脸图片用一个列向量表示,即对于128*128的图片,将视为16384维的列向量),A的列数就是图片的张数。算法就是求矩阵C的特征向量,每个向量称之为特征脸[1]。为了简单,只取其中部分的特征向量,这些特征向量对应于某些特征值,通常是前M个大的特征值。这样便得到了M个特征向量。接下来就是将每张图片在这M个特征向量上做投影,得到一个M维的权重向量w=(w1,…wM),一个人可能有多张图片,于是将对应于这个人的权重向量做一个平均作为这个人的权重向量。然后对于每个新来的人脸,先求得一个权重向量,然后与人脸库中每个人的权重向量做比较,如果小于某个阈值,则认为他是人脸库中的这个人;否则视为unknown。当然,文章中还给出了另外一个判断一张图像是否是人脸的方法,这里不再讨论。对于计算的时候我们实际上求的是ATA,至于二者的关系,可以参考文章[1],因为与后面讨论的关系不大,这里不细说了。
有个上述简介,我们就大概知道了PCA到底是怎么做的了。刨根问底一下,C到底是什么,C的特征向量又到底是什么,对应于特征值大的特征向量有有什么意义。
1.C到底是什么?我们先看一下C的(i,j)元素是什么。很简单,就是A的第i行与AT的第j列的乘积。那么A的第i行又是什么呢?就是每张图片的第i个像素构成的一个向量。则C的(i,j)元素就是每张图片的第i个像素构成的向量与每张图片的第j个像素构成的向量的乘积。回忆一下概率论中的协方差cov(x,y)=E((x-x)(y- y)),这里x– 是x的平均。如果我们把图片的第i个像素视为一个随机变量Xi,那么人脸库中的每张人脸的第i个像素的取值即为这个随机变量的所有取值。根据注,A的第i行的每个值都已经减去了Xi的均值,因此C的(i,j)元素就是随机变量Xi与Xj的协方差。到此,我们已经知道C是什么了。
2.C的特征向量是什么。我们知道对C求特征向量是找到一个可逆矩阵Q,使得Q-1CQ是一个对角阵D,D的元素即为特征值,Q中的每一列即为特征向量,与特征值所在的列一一对应。注意,因为C是实对称阵,故必然可以对角化。由于C是对称的,C的特征向量是正交的,因此Q便是一个正交阵,故Q-1即为QT。先从简单的角度来看,假设C已经是一个对角阵了,并且对角元素依次递减。即随机变量Xi与Xj(i!=j)时是不相关的,而Xi的方差则随着i的增大而减小。也就是前几个像素是方差比较大的像素,即在第一个像素上,每张图片的值变化最大,第二个像素次之,依此类推。举个例子,假设第一个像素表示人脸的额头上的某个点(也许你会问,第一个像素不是图片的最左上角的那个像素吗?为什么会是额头上的某个点,后面会说明为什么可以这么假设),而在这个点上,有些人有痣,有些人没有,那么这一点的方差就会比相邻的额头上的其他点大,因为其他点上,每个人的额头都差不多,因此其像素值也差不多,方差就小了。现在来考虑QTAATQ=D,这里依然假设D中的元素依次递减。对于QTA,QT的每一行是一个特征向量,QT的第i行与A的每一列相乘得到QTA的每一行,从矩阵的角度也可以看作是用QT对A做一个变换。记住这里的QTA可以看做前面讨论的A,那么变换的结果就是使得QTA前面的行对应的是方差大的像素,而且这个变换会把方差最大的放到了第一行(因为D的降序排列),这里也就解释了为什么前面那个例子可以认为第一个像素是额头上的某个点,因为做了变换。我们选择了QT的前M行作为特征向量,因为他们对应了前M个大的特征值。这里可以举一个直观但是不一定恰当的例子,人的头发部分对应的那些像素,经过QT变换后回到某个像素上,那么这个像素会是QTA中的哪个位置呢,我认为应该是QTA的列中靠下面的像素,因为在头发这个像素的地方每个人基本都是头发(这句话很别扭,我是想说,对于比较正规的人脸库,即每张人脸不会有太大的变化,某个人头发的对应的那几个像素对于其他人来说也都是头发,因此变换后这个像素对于每个人都差不多,方差小,固然会在比较靠后的位置了)。QTA的每一列的前M个元素对应的就是每张人脸的权重向量w。因此每张人脸的权重向量的同一个分量可以看作是新的像素,这些新的像素对应着方差依次减小的像素。对于一张新来的人脸,让他在特征向量上作投影得到权重向量,在这些方差大的像素处,如果跟某个人的比较接近,则认为是这个人,这个也是合理的。至此,也许没能讲清楚特征向量是什么,但我想对应于特征值大的特征向量有什么意义这一点也交代的差不多了。
3.2中交代了说了,这里想不到有什么需要补充的了。
理解了这几个问题之后,PCA简洁明了(这本来就是的)而又有深刻意义了。我突然发现原来看似简单的理论其实水深的很,o(︶︿︶)o !我看文章实在是不够认真,如果没有师兄提问,估计我也不会去想这个问题。再次感谢WF师兄。
 
[1]Eigenfaces for Recognition. Matthew Turk,Alex Pentland 1991
注:A的每一列是一张人脸,这里的人脸是每张人脸减去了所有人脸的平均后的人脸

Categories
不学无术

1019. General Palindromic Number (20)

A number that will be the same when it is written forwards or backwards is known as a Palindromic Number. For example, 1234321 is a palindromic number. All single digit numbers are palindromic numbers.
Although palindromic numbers are most often considered in the decimal system, the concept of palindromicity can be applied to the natural numbers in any numeral system. Consider a number N > 0 in base b >= 2, where it is written in standard notation with k+1 digits ai as the sum of (aibi) for i from 0 to k. Here, as usual, 0 <= ai < b for all i and ak is non-zero. Then N is palindromic if and only if ai = ak-i for all i. Zero is written 0 in any base and is also palindromic by definition.
Given any non-negative decimal integer N and a base b, you are supposed to tell if N is a palindromic number in base b.
Input Specification:
Each input file contains one test case. Each case consists of two non-negative numbers N and b, where 0 <= N <= 109 is the decimal number and 2 <= b <= 109 is the base. The numbers are separated by a space.
Output Specification:
For each test case, first print in one line “Yes” if N is a palindromic number in base b, or “No” if not. Then in the next line, print N as the number in base b in the form “ak ak-1 … a0“. Notice that there must be no extra space at the end of output.
Sample Input 1:

27 2

Sample Output 1:

Yes
1 1 0 1 1

Sample Input 2:

121 5

Sample Output 2:

No
4 4 1

===========================
最近产量太低,都是有小bug的答案,唯独这道题终于。。。。
其实这道题相当简单,不想说啥了
时间空间都没有限制,如果机试碰到这种题,那估计是八辈子修来的福。。。
直接贴答案吧。。
===========================

#include 
using namespace std;
long resultSize = 0;
const int MAX_BUFF_SIZE = 30;
int buff[MAX_BUFF_SIZE];
void calcBase(long inputVal, long base)
{
	//计算以base为低的inputVal的值
	if(inputVal == 0)
	{
		resultSize = 1;
		buff[0] = 0;
		return;
	}
	resultSize = 0;
	while(inputVal > 0)
	{
		buff[resultSize++] = inputVal % base;
		inputVal /= base;
	}
}
bool isPalindrome()
{
	long limit = resultSize /2;
	for(long i=0; i> a >> b;
	calcBase(a, b);
	if( isPalindrome())
		cout << "Yes" << endl;
	else
		cout << "No" << endl;
	while(--resultSize)
	{
		cout << buff[resultSize] << " ";
	}
	cout << buff[0];
	return 0;
}
Categories
不学无术

vi 操作笔记

本文转载自:
http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/10/14/2211202.html
======================================
1.关于退出

:wq!  ----强制保存退出
:wq  ---- 保存退出
:x   ----- 作用和:wq 一样
ZZ  ---- 作用和:wq一样,(注意Z是大写的,并且不是在命令模式)
:q  ---- 退出
:q!  ---  强制退出

 
==============================================
2.关于移动
h : 在当前行向左移动一个字符
j:  移动到下一行
k:  移动到上一行
l:  在当前行向右移动一个字符
Ctrl +f:  向前滚动一页
Ctrl +b:  向后滚动一页
:n   将光标定位到第n行
:$   将光标定位到最后一行
0   将光标定位到本行的行首
$   将光标定位到本行的行尾
G   将光标定位到本文章的最后一行,与:   $功能相同。
H   将光标定位到屏幕的顶端
M   将光标定位到屏幕的中间
L   将光标定位到屏幕的底端
============================================
3.关于搜索
/:   后面跟要查找的东西,在文件中向前搜索
?:  后面跟要查找的东西,在文件中向后搜索
n:  向前重复搜索
N:  向后重复搜索
=============================================
4.关于复制
yy:  复制光标当前行
nyy:  复制光标当前行到当前行以下的n-1行
:1,100 co 200   将1~100的内容复制到第200行。
:100,102 co $   将100~102行的内容复制到最后一行。
==============================================
5.关于粘贴
p :   粘贴到当前行的下一行
P(大) :   粘贴到当前行的 上一行
==============================================
6.关于删除.剪切

dd   删除当前行
ndd   与nyy相似
dw   删除一个单词
ndw   与ndd相似
x    删除一个字符
nx   删除n个字符
dG   删除当前光标到文件末尾的所有内容。
d0   删除当前光标到本行行首的所有内容
d$   删除当前光标到本行行尾的所有内容
:1,100d  删除1~100
:100d    删除第100行
:1,100 mo $   将1~100行的内容移动到最后一行。
=============================================
7.关于插入
i:  在当前位置的字符前面进入插入模式
I:  在当前行的开头进行插入
a:  在当前位置的字符后面进入插入模式
A:  在当前行的结尾进行插入
o:  在当前行下面打开一个新行进行插入
O:  在当前行上面打开一个新行进行插入
=============================================
8.关于撤销
 
u:  撤销上一次的更改
=============================================
9.关于替换
regexp:  是要匹配的式样
replacement:  是要替换的字符串
:s/regexp/replacement   ————————-替换当前行出现的第一个式样
:s/regexp/replacement/g  ————————-替换当前行所有的匹配
:%s/regexp/replacement/g  ———————–替换文件中所有匹配式样
=============================================
PS:  还有一个重要的命令就是”.” 命令,这个命令是用来重复上一命令的
 
vi里如何:撤销上次操作?,多次重复一组编辑操作?…….
 
a)   撤消上一个编辑操作。       ====>   u
b)   重复上一个编辑操作。     =====>   .
c)   还原被撤消的编辑操作。   ======>   Ctrl   +   R
d)   多次重复一组编辑操作。 ====>  “. ” 命令可以重复最近一次的编辑动作.
 
 

 
 
 
 

《鸟哥的Linux私房菜》vi 讲义

 

Categories
木有技术

如何在 VPS 上搭建 PPTP/L2TP VPN 简易教程

首先是L2TP的,来自http://www.kukaka.org/home/content/640

如之前所说,PPTP 类的 VPN 可以在 iPhone 手机上使用,但是不能在 Mac OS X 电脑系统上使用,于是,我需要使用 L2TP/IPSec (L2TP over IPSec,即在 IPSec 上搭建 L2TP) 类的 VPN。
这篇文章将介绍如何在 VPS (Xen)上搭建 L2TP/IPSec 类的 VPN,而你只需要一个 VPS 和一台可以上网的电脑。和 PPTP 的一样,L2TP/IPSec 的操作步骤也是基于 Mac 电脑的终端应用程序,对 Linux 系统来讲,步骤几乎是一模一样的,而对 Windows 用户来讲,则需要先安装一个叫 Putty 的软件。
顺便提一下,Xen VPS 的 Ubuntu 系统最好使用 11.04 版本的,因为其他较低的版本(例如 10.04)很可能不行。
 

I、连接 VPS

打开终端应用程序并输入以下命令:
ssh [email protected]
记得将 “xxx.xxx.xxx.xxx” 替换成 VPS 的 IP 地址,例如 “178.18.17.30”,然后回车就可以了。
P.S.:
如果在连接的过程中遇到问题,可以参考之前的 PPTP 教程。

II、安装 OpenSwan

虽然你可以通过输入 “aptitude install openswan” 命令直接安装 OpenSwan,但根据我分别在两个不同的 VPS 上测试的结果,这种方法已经无效,所以,最好还是直接从 OpenSwan 官方网站下载再安装,具体方法如下:

1、输入以下命令:

aptitude install build-essential
回车,输入 “y”,再回车。

2、输入以下命令:

aptitude install libgmp3-dev gawk flex bison
回车,输入 “y”,再回车。

3、输入以下命令:

wget http://www.openswan.org/download/openswan-2.6.35.tar.gz
回车。

4、输入以下命令:

tar xzvf openswan-2.6.35.tar.gz
回车。

5、输入以下命令:

cd openswan-2.6.35
回车。

6、输入以下命令:

make programs
回车。

7、输入以下命令:

make install
回车。到此,OpenSwan 就安装成功了。
备注:
a、2.6.35 是目前最新的版本,将来你可以访问 OpenSwan 官方网站看看有没有更新的版本,如有,不妨尝试一下。
b、文章中的所有命令都可以直接复制粘贴到终端应用程序。

III、编辑 IPSec

OpenSwan 是用来建 IPSec 的,而 IPSec 是用来建 L2TP 的。

1、输入以下命令:

vi /etc/ipsec.conf
回车,输入 “dG” 删除所有内容,按 “i” 键,然后复制并粘贴以下内容:
version 2.0
config setup
    nat_traversal=yes
    virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v6:fd00::/8,%v6:fe80::/10
    oe=off
    protostack=netkey
conn %default
    forceencaps=yes
conn L2TP-PSK-NAT
    rightsubnet=vhost:%priv
    also=L2TP-PSK-noNAT
conn L2TP-PSK-noNAT
    authby=secret
    pfs=no
    auto=add
    keyingtries=3
    rekey=no
    ikelifetime=8h
    keylife=1h
    type=transport
    left=YOUR.VPS.IP.ADDRESS
    leftprotoport=17/1701
    right=%any
    rightprotoport=17/%any
记得将 YOUR.VPS.IP.ADDRESS 替换成自己 VPS 的 IP 地址,例如 178.18.17.30。替换方法如下:
按下”ESC” 键退出插入模式,将光标移到 “Y” 字母上,接着按下 “i” 键,输入 IP 地址,再按一下 “ESC” 键,并将光标移到 “YOUR.VPS.IP.ADDRESS” 上,然后按下 “x” 键把它们全部删除。或者你可以先把内容粘贴到记事本之类的编辑器上并修改好之后再复制粘贴到终端应用程序。
完了之后,输入 “:wq” 并回车保存所做的修改。
备注:
在 Vi 编辑模式下,你需要按 “i” 才能插入内容,完了之后,要按 “ESC” 退出插入模式和保存。

2、输入以下命令:

vi /etc/ipsec.secrets
回车,按 “i” 键并输入以下内容:
YOUR.VPS.IP.ADDRESS %any: PSK “YourSharedSecret”
例如:
178.18.17.30 %any: PSK “123456abcdef”
(小技巧:你需要按 Tab 键创建不同数值之间的空格。)
按 “ESC” 键,输入 “:wq”,再回车保存。

3、一行一行地输入以下命令:

for each in /proc/sys/net/ipv4/conf/*
do
echo 0 > $each/accept_redirects
echo 0 > $each/send_redirects
done
每一行都要回车。

4、输入以下命令:

service ipsec restart
回车。
备注:
输入 “ipsec verify”,回车,如果一切正确,你将会看到如下图所示的结果:
如果不是,则需要重新检查之前的操作步骤,特别是 “ipsec.conf” 的内容。

IV、安装 L2TP

基于 IPSec 的 L2TP 就是 VPN 了。

1、输入以下命令:

cd ..
回车以便进入 VPS 根目录。

2、输入以下命令:

aptitude install xl2tpd
回车,输入 “y”,再回车。

3、输入以下命令:

vi /etc/xl2tpd/xl2tpd.conf
回车,输入 “dG” 删除所有的内容,按下 “i” 键,然后粘贴以下内容:
[global]
; listen-addr = 192.168.1.98
[lns default]
ip range = 10.1.1.2-10.1.1.255
local ip = 10.1.1.1
require chap = yes
refuse pap = yes
require authentication = yes
name = LinuxVPNserver
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
按下 “ESC” 键,输入 “:wq”,并回车保存。

V、创建 xl2tpd

这里假设你的 VPS 已经支持 PPP,如果没有,先输入 “aptitude install ppp” 命令安装 PPP。

1、输入以下命令:

vi /etc/ppp/options.xl2tpd
回车,按下 “i” 键,然后粘贴以下内容:
require-mschap-v2
ms-dns 8.8.8.8
ms-dns 8.8.4.4
asyncmap 0
auth
crtscts
lock
hide-password
modem
debug
name l2tpd
proxyarp
lcp-echo-interval 30
lcp-echo-failure 4
按下 “ESC” 键,输入 “:wq”,并回车保存。
备注:
你可以将 8.8.8.8 和 8.8.4.4 替换成 208.67.222.222 和 208.67.220.220。

2、输入以下命令:

vi /etc/ppp/chap-secrets
回车,按下 “i” 键,并输入如下内容:
username l2tpd password *
例如:
freenuts l2tpd 123456 *
记得用 “tab” 键输入空格,用 “:wq” 保存文件。

3、输入以下命令:

service xl2tpd restart
回车。

VI、IP 转发

这个步骤将使你的 VPN 连接整个互联网。

1、输入以下命令:

vi /etc/sysctl.conf
回车,找到 “#net.ipv4.ip_forward=1” 这一行,接着按 “x” 键删除 “#” 号,然后输入 “:wq” 保存。

2、使转发生效:

sysctl -p
回车,如果一切正常,你将会只看到以下结果:
net.ipv4.ip_forward = 1

3、输入以下命令:

iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o eth0 -j MASQUERADE
回车之后,你就可以连接自己的 L2TP/IPSec VPN 翻墙了,但是如果你重启 VPS 的话,就需要重新执行一次 iptables 命令,并重启 ipsec,为了避免这些,你只需要输入以下命令:
vi /etc/rc.local
并在 “exit 0” 这一行之前粘贴以下内容就可以了:
for each in /proc/sys/net/ipv4/conf/*
do
echo 0 > $each/accept_redirects
echo 0 > $each/send_redirects
done
iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -o eth0 -j MASQUERADE
/etc/init.d/ipsec restart
完了之后,你就可以尽情地享用自己搭建的 L2TP/IPSec VPN 了。
额外收获:
以下是根据上面的教程在 2host 的 Xen VPS 上搭建的 L2TP/IPSec VPN:
Server Address: 178.18.17.30
Account Name: freenuts
Password: 123456
Shared Secret: 123456abcdef
这个 VPN 帐号会免费大概半个月,你可以参考这篇文章 在电脑或者手机上试用。
=====================================================

然后是PPTP的(这种方便一些)

在 Ubuntu 上搭建 VPN 服务器的方法非常多,比较著名的有 PPTP, L2TP/IPSec 和 OpenVPN。这里介绍一下pptp的安装配置方法。
服务器环境是单网卡 eth0。
在 Ubuntu 中建立 pptp server 需要的软件包为 pptpd,用 apt-get 即可安装:
sudo apt-get pptpd
安装好后,首先编辑 /etc/pptpd.conf
sudo vi /etc/pptpd.conf
去掉文件最末端的 localip 和 remoteip 两个参数的注释,并进行相应修改。这里,localip 是 VPN 连通后服务器的 ip 地址,而 remoteip 则是客户端的可分配 ip 地址。
localip 10.100.0.1
remoteip 10.100.0.2-10
编辑好这个文件后,我们需要编辑 /etc/ppp/pptpd-options 文件,我们只需要改变其中的 ms-dns 选项,为 VPN 客户端指派 DNS 服务器地址:
ms-dns 202.113.16.10
ms-dns 208.67.222.222
修改 /etc/ppp/chap-secrets 文件,这里面存放着 VPN 的用户名和密码,根据你的实际情况填写即可。如文件中注释所示,第一列是用户名,第二列是服务器名(默认写 pptpd 即可,如果在 pptpd-options 文件中更改过的话,注意这里保持一致),第三列是密码,第四列是 IP 限制(不做限制写 * 即可)。
全部搞定后,我们需要重启 pptpd 服务使新配置生效:
sudo /etc/init.d/pptpd restart
找一台 Windows 电脑,新建个 VPN 链接,地址填服务器的 IP(或域名),用户名密码填刚才设置好的,域那项空着(如果你在 pptpd-options 中设置了,这里就保持一致),点连接就可以了。正常情况下您应该能够建立与服务器的 VPN 链接了。
建立连接之后,您会发现除了可以访问服务器的资源,其余内外和互联网的内容均无法访问。如果需要访问这些内容的话,我们还需要进一步设置:
首先,开启 ipv4 forward。方法是,修改 /etc/sysctl.conf,找到类似下面的行并取消它们的注释:
net.ipv4.ip_forward=1
然后使新配置生效:
sudo sysctl -p
有些时候,经过这样设置,客户端机器就可以上网了(我在虚拟机上这样操作后就可以了)。但我在实验室的服务器上这样操作后仍然无法访问网络,这样我们就需要建立一个 NAT。这里我们使用强大的 iptables 来建立 NAT。首先,先安装 iptables:
sudo apt-get intall iptables
装好后,我们向 nat 表中加入一条规则:
sudo iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
这样操作后,客户端机器应该就可以上网了。
但是,只是这样,iptables 的规则会在下次重启时被清除,所以我们还需要把它保存下来,方法是使用 iptables-save 命令:
sudo iptables-save > /etc/iptables-rules
然后修改 /etc/network/interfaces 文件,找到 eth0 那一节,在对 eth0 的设置最末尾加上下面这句:
pre-up iptables-restore < /etc/iptables-rules
这样当网卡 eth0 被加载的时候就会自动载入我们预先用 iptables-save 保存下的配置。
到此,一个 VPN Server/Gateway 基本就算架设完毕。当然,也许你按照我的方法做了,还是无法成功,那么下面总结一些我碰到的问题和解决方案:
无法建立 VPN 连接
安装好 pptpd 并设置后,客户端还是无法建立到服务器的连接。造成的原因可能有以下几种:
1. 服务器端的防火墙设置:PPTP 服务需要使用 1723(tcp) 端口和 gre 协议,因此请确保您的防火墙设置允许这两者通行。
2. 如果服务器在路由器后面,请确保路由器上做好相应的设置和端口转发。
3. 如果服务器在路由器后面,那么请确保你的服务器支持 VPN Passthrough。
4. 如果客户端在路由器后面,那么客户端所使用的路由器也必须支持 VPN Passthrough。其实市面上稍微好点的路由器都是支持 VPN Passthrough 的,当然也不排除那些最最最便宜的便宜货确实不支持。当然,如果你的路由器可以刷 DD-Wrt 的话就刷上吧,DD-Wrt 是支持的。
能建立链接,但“几乎”无法访问互联网
这里我使用“几乎”这个词,是因为并不是完全不能访问互联网。症状为,打开 Google 搜索没问题,但其它网站均无法打开;SSH 可用,但 scp 不行;ftp 能握手,但传不了文件。我就遇到了这种情况,仔细 Google 后发现原来是 MTU 的问题,用 ping 探测了一下果然是包过大了。知道问题就好办了,我们可以通过 iptables 来修正这一问题。具体原理就不讲了,需要的自己 Google。这里只说解决方案,在 filter 表中添加下面的规则:
sudo iptables -A FORWARD -s 10.100.0.0/24 -p tcp -m tcp –tcp-flags SYN,RST SYN
-j TCPMSS –set-mss 1200
上面规则中的 1200 可以根据你的实际情况修改,为了保证最好的网络性能,这个值应该不断修改,直至能保证网络正常使用情况下的最大值。
好了,至此,一台单网卡 pptp-server 就算完成了。
这篇来自http://www.study365.org/linux/30.html
=====================================================
附加教程:

Ubuntu搭建VPN服务器pptpd安装配置http://www.study365.org/linux/30.html

centos 5搭建vpn服务器请访问http://www.study365.org/linux/60.html

Categories
不学无术

Sleeping barber problem (睡觉的理发师问题)

今天做操作系统作业碰到的问题,一时想不出怎么做,后来Google了一下发现是个经典问题。
=========================================================================
以下英文内容转载自:http://www.answers.com/topic/sleeping-barber-problem
本人的理解继续往下看。
In computer science, the sleeping barber problem is a classic inter-process communication and synchronization problem between multiple operating system processes. The problem is analogous to that of keeping a barber working when there are customers, resting when there are none and doing so in an orderly manner.
The analogy is based upon a hypothetical barber shop with one barber. The barber has one barber chair and a waiting room with a number of chairs in it. When the barber finishes cutting a customer’s hair, he dismisses the customer and then goes to the waiting room to see if there are other customers waiting. If there are, he brings one of them back to the chair and cuts his hair. If there are no other customers waiting, he returns to his chair and sleeps in it.
Each customer, when he arrives, looks to see what the barber is doing. If the barber is sleeping, then the customer wakes him up and sits in the chair. If the barber is cutting hair, then the customer goes to the waiting room. If there is a free chair in the waiting room, the customer sits in it and waits his turn. If there is no free chair, then the customer leaves. Based on a naïve analysis, the above description should ensure that the shop functions correctly, with the barber cutting the hair of anyone who arrives until there are no more customers, and then sleeping until the next customer arrives. In practice, there are a number of problems that can occur that are illustrative of general scheduling problems.
The problems are all related to the fact that the actions by both the barber and the customer (checking the waiting room, entering the shop, taking a waiting room chair, etc.) all take an unknown amount of time. For example, a customer may arrive and observe that the barber is cutting hair, so he goes to the waiting room. While he is on his way, the barber finishes the haircut he is doing and goes to check the waiting room. Since there is no one there (the customer not having arrived yet), he goes back to his chair and sleeps. The barber is now waiting for a customer and the customer is waiting for the barber. In another example, two customers may arrive at the same time when there happens to be a single seat in the waiting room. They observe that the barber is cutting hair, go to the waiting room, and both attempt to occupy the single chair.
The Sleeping Barber Problem is often attributed to Edsger Dijkstra (1965), one of the pioneers in computer science.
Many possible solutions are available. The key element of each is a mutex, which ensures that only one of the participants can change state at once. The barber must acquire this mutex exclusion before checking for customers and release it when he begins either to sleep or cut hair. A customer must acquire it before entering the shop and release it once he is sitting in either a waiting room chair or the barber chair. This eliminates both of the problems mentioned in the previous section. A number of semaphores are also required to indicate the state of the system. For example, one might store the number of people in the waiting room.
multiple sleeping barbers problem has the additional complexity of coordinating several barbers among the waiting customers.

Implementation

  • The following pseudocode guarantees synchronization between barber and customer and is deadlock free, but may lead to starvation of a customer. The functions wait() and signal() are functions provided by the semaphores.
# The first two are mutexes (only 0 or 1 possible)
Semaphore barberReady = 0
Semaphore accessWRSeats = 1     # if 1, the # of seats in the waiting room can be incremented or decremented
Semaphore custReady = 0         # the number of customers currently in the waiting room, ready to be served
int numberOfFreeWRSeats = N     # total number of seats in the waiting room
def Barber():
  while true:                   # Run in an infinite loop.
    wait(custReady)             # Try to acquire a customer - if none is available, go to sleep.
    wait(accessWRSeats)         # Awake - try to get access to modify # of available seats, otherwise sleep.
    numberOfFreeWRSeats += 1    # One waiting room chair becomes free.
    signal(barberReady)         # I am ready to cut.
    signal(accessWRSeats)       # Don't need the lock on the chairs anymore.
    # (Cut hair here.)
def Customer():
  while true:                   # Run in an infinite loop to simulate multiple customers.
    wait(accessWRSeats)         # Try to get access to the waiting room chairs.
    if numberOfFreeWRSeats > 0: # If there are any free seats:
      numberOfFreeWRSeats -= 1  #   sit down in a chair
      signal(custReady)         #   notify the barber, who's waiting until there is a customer
      signal(accessWRSeats)     #   don't need to lock the chairs anymore
      wait(barberReady)         #   wait until the barber is ready
      # (Have hair cut here.)
    else:                       # otherwise, there are no free seats; tough luck --
      signal(accessWRSeats)     #   but don't forget to release the lock on the seats!
      # (Leave without a haircut.)

============================

本人观点:
其中需要共享的数据应该只有可用的座椅数目(numberOfFreeWRSeats),但是需要改动这个座椅数目的过程比较繁杂…原本以为N是用作信号量里面的,但是这个解决方案来看是把他作为额外的变量。
为什么N不能做信号量?后来想了一下..这个东西是共享的资源…明显不能拿来做信号量的吧。
文中3个信号量

Semaphore barberReady = 0
Semaphore accessWRSeats = 1     # if 1, the # of seats in the waiting room can be incremented or decremented
Semaphore custReady = 0         # the number of customers currently in the waiting room, ready to be served

其中barberReady是理发师就绪的信号量,barber讲客人请入理发室后,signal一下,然后示意客户可以开始理发了,客户那边wait这个信号量,等到了就开始理发过程。这个是一个同步的关系,因为肯定是要理发师先准备好,然后客人才可以开始理发,这两个动作有顺序要求,所以信号量初值设置成0.
第二个accessWRSeats是用来锁座椅数目改变的,锁住(=0)的时候,说明waitingroom内有人员变动中,要阻塞其他人对人员变动的尝试。显然这是一个互斥量(mutex),当客人进入理发室准备理发时、或者理发店外有人进入时,都要改变numberOfFreeWRSeats这个量,这种操作显然是独占的,同时只能有一方来修改这个值,所以引入此信号量协调。
第三个嘛..客人就绪的信号量,主要原因是barber空闲下来的时候需要睡大觉。这个与第一个信号量一样,是一个同步的问题。即客人先要准备好了,才能把理发师唤醒做事情,不然就别吵到他。
三个信号量理解了,后面的过程也就一目了然了。不知道我说的对不对…
这个问题应该有另一(或多)种解法,另一种解法是指会导致barber的starvation的解法,或者是权衡两者折中的办法,这个没有多想过。

Categories
不学无术 木有技术

【Android Camera】之 Preview

本文转载自:

http://blog.csdn.net/yiyaaixuexi/article/details/6455741

================================================================
实在不好复制过来,去原文看吧。

Categories
木有技术

ThinkPad RnR 系统恢复盘 IMD IMZ 文件解压密码表

本文转载自:
http://forum.51nb.com/thread-1343052-1-1.html
=================================
ThinkPad RnR 系统恢复盘 IMD IMZ 文件解压密码表

ENCYPTED DECRYPTED PASSWORD
BMGR be0d
HURRICANES xwbdbgmlbu
HUURICANES xwvdbgmlbu
STANLEYCUP u1kmkblhvi
TVTPASS 2b0ilsu
CKD158A iqyrabm
CKD164T iqyrhk2
CKD170T iqyrzm2
CKD171A iqyrzpm
CKD173T iqyrzd2
CKD174T1 iqyrzk2q
CKD179T iqyrzs2
CKD185T1 iqyrc`2q
CKD192T iqyrtj2
CKD196T iqyrtg2
CKD197T iqyrty2
CKD199T iqyrts2
CKD204A iqylnkm
CKD205T iqyln`2
BKD010F bqyoqmu
BKD023F bqyokdu
BKD0025F bqyonjbt
BKD037A bqyoeym
BKD047F bqyolyu
CM2ZCFR iejfhsd
以上是已被别人解开的密码,
以下是别人通过以上密码绘制的对应图表:

Thinkpad RnR 系统恢复盘 密码表
Thinkpad RnR 系统恢复盘 密码表

以下是我通过上面的对应图表列出的X60 7CD XP恢复盘文件的密码,成功解压无误。
2GLGU31_  ickb1bdc
3GZUM0A0  fljbcbdk
CKD158A   iqyrabm
CKD1642   iqyrhkl
CKD1702   iqyrzml
CKD171A   iqyrzpm
CKD1732   iqyrzdl
CKD17421  iqyrzklq
CKD1792   iqyrzsl
CKD1852   iqyrc`l
CKD1922   iqyrtjl
CKD1962   iqyrtgl
CKD1972   iqyrtyl
CKD1992   iqyrtsl
CKD204A   iqylnkm
XM2AACS   rejmlgu
XM2UACS   rejxlgu
TVTPASS   2b0ilsu
图表来自“http://forum.notebookreview.com/ … vice-partition.html
向那些神人致敬!

Categories
不学无术 木有技术

1042. Shuffling Machine (20)

Shuffling is a procedure used to randomize a deck of playing cards. Because standard shuffling techniques are seen as weak, and in order to avoid “inside jobs” where employees collaborate with gamblers by performing inadequate shuffles, many casinos employ automatic shuffling machines. Your task is to simulate a shuffling machine.
The machine shuffles a deck of 54 cards according to a given random order and repeats for a given number of times. It is assumed that the initial status of a card deck is in the following order:
S1, S2, …, S13, H1, H2, …, H13, C1, C2, …, C13, D1, D2, …, D13, J1, J2
where “S” stands for “Spade”, “H” for “Heart”, “C” for “Club”, “D” for “Diamond”, and “J” for “Joker”. A given order is a permutation of distinct integers in [1, 54]. If the number at the i-th position is j, it means to move the card from position i to position j. For example, suppose we only have 5 cards: S3, H5, C1, D13 and J2. Given a shuffling order {4, 2, 5, 3, 1}, the result will be: J2, H5, D13, S3, C1. If we are to repeat the shuffling again, the result will be: C1, H5, S3, J2, D13.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer K (<= 20) which is the number of repeat times. Then the next line contains the given order. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print the shuffling results in one line. All the cards are separated by a space, and there must be no extra space at the end of the line.
Sample Input:

2
36 52 37 38 3 39 40 53 54 41 11 12 13 42 43 44 2 4 23 24 25 26 27 6 7 8 48 49 50 51 9 10 14 15 16 5 17 18 19 1 20 21 22 28 29 30 31 32 33 34 35 45 46 47

Sample Output:

S7 C11 C10 C12 S1 H7 H8 H9 D8 D9 S11 S12 S13 D10 D11 D12 S3 S4 S6 S10 H1 H2 C13 D2 D3 D4 H6 H3 D13 J1 J2 C1 C2 C3 C4 D1 S5 H5 H11 H12 C6 C7 C8 C9 S2 S8 S9 H10 D5 D6 D7 H4 H13 C5

===================================
本题目主要难度:英语阅读。
就是数组里面元素换来换去没啥好说的,就是发现自己数组指针这块了解的不是很清晰,以后得注意。
===================================

#include 
#include 
using namespace std;
const int SUFF_SIZE = 54;
int *cards = new int[SUFF_SIZE]; //扑克牌数组
int *results = new int[SUFF_SIZE];
int* suffle(int * src, int* rule)
{
	for(int i=0; i= 10)
	{
		result += "1";
		postfix = postfix%10;
	}
	result += (char)(postfix + 0x30);
	return result;
}
int rules[SUFF_SIZE]; //suffle规则
int main()
{
	int K;
	cin >> K;
	for(int i=0; i> rules[i];
	}
	while(K--)
	{
		suffle(cards, rules);
		for(int i=0; i

		
Categories
生活琐碎

不错的书

以下三本书最近在看,觉得不错:

  • 《Head First Python》,编程语言入门Head First系列一直听别人说不错,前两天头脑发热不惜重金从亚马逊买了一本,看着果然还不错,推荐初学者使用。
  • 《编程珠玑(第二版)》讲一些很有用的常识,看来一点点
  • 《人月神话》,软件工程方面的书,据说是经典,下了个pdf放在kindle上面看,还不错的感觉

另外鄙视下某些商科高富帅,想在半个月内找一些不靠谱的人组个团队做个完善可用的电商网站,做梦去吧呵呵。如果想法都能那么轻易实现的话,世界上早就都是富翁了,不就是没钱请外包公司么,还美其名曰创业项目,都不想吐槽了,不知道香港评委瞎了眼了还是怎么的,这种想法怎么可能实现?国内电商掐架弄得不亦乐乎了,校园内做推广有什么意思,相比校外平台除了可能可以上门递送之外有什么优势?价格比得过淘宝JS?售后能玩的过京东亚马逊?人链能搞得过腾讯的易迅?优势可能是递送时间吧,但是真正要做创业的话,雇人递送还不如做个领快递的网站,把最后一公里的问题解决了来的靠谱。看了他们的项目计划,定位都不清晰。格子铺就是个租地方给人经营的容器,网络的格子铺还不是电商么,不知道为什么叫形式新颖了。团宣一帮老师还说资金丰厚,呵呵,50元么?团委给报销的资金额度真是问谁谁都知道了,竟然还有报销10块钱的》。。。
没办法,作为屌丝码农,只能默默地不作为,因为发现想的越多,这事情越不可能实现。

Categories
不学无术 木有技术

第二章 啊哈!算法

原文见:

http://blog.csdn.net/silenough/article/details/7040028

 
A. 给定一个最多包含40亿个随机排列的32位整数的顺序文件,找出一个不在文件中的32位整数(在文件中至少缺少一个这样的数—为什么?)。在具有足够内存的情况下,如何解决该问题?如果有几个外部的“临时”文件可用,但是仅有几百字节的内村,又该如何解决该问题?
因为2^32 大于40亿,所以文件中至少缺失一个整数。我们从表示每个整数的32位的视角来考虑二分搜索,算法的第一趟(最多)读取40亿个输入整数,并把起始位为0的整数写入一个顺序文件,把起始位为1的整数写入另一个顺序文件。这两个文件中,有一个文件最多包含20亿个整数,接下来将该文件用作当前输入并重复探测过程,但这次探测的是第二个位。如果原始的输入文件包含n个元素,那么第一趟将读取n个整数,第二趟最多读取n/2个整数,第三趟最多读取n/4个整数,依次类推,所以总的运行时间正比于n。
如果内存足够,采用位图技术,通过排序文件并扫描,也能够找到缺失的整数,但是这样做会导致运行时间正比于nlog(n).
1. 考虑查找给定输入单词的所有变位词的问题。仅给定单词和字典的情况下,如何解决该问题?如果有一些时间和空间可以在响应任何查询之前预先处理字典,又会如何?
首先计算给定单词的标识,若果不允许预处理,那么久只能顺序读取整个文件,计算每个单词的标识,并于给定单词的标识进行比较。
 

  1. //压缩一个单词,形成其标识,设定单词中相同字母不会超过99个
  2. void compress(char * pWord, int len, char * pFlag)
  3. {
  4.     sort(pWord, pWord+len); //对单词进行排序
  5.     int i = 0;
  6.     int nCount;            //计数重复字母的个数
  7.     char chCount[3];       //存放整数到字符的转换值,整数最大为99
  8.     while (*pWord != ‘’)
  9.     {
  10.         char chTemp = *pWord;
  11.         char *pTemp = pWord + 1;
  12.         nCount = 1;
  13.         while (true)
  14.         {
  15.             if (chTemp == *pTemp++)
  16.             {
  17.                 ++nCount;
  18.             }
  19.             else
  20.             {
  21.                 *(pFlag + i++) = *pWord;
  22.             //  ++i;
  23.                 memset(chCount, ‘’, 3);
  24.                 _itoa(nCount, chCount, 10);
  25.                 if (nCount >= 10)
  26.                 {
  27.                     *(pFlag + i++) = *(chCount + 0);
  28.                 //  i++;
  29.                     *(pFlag + i++) = *(chCount + 1);
  30.                 //  ++i;
  31.                 }
  32.                 else
  33.                 {
  34.                     *(pFlag + i++) = *(chCount + 0);
  35.                 //  ++i;
  36.                 }
  37.                 pWord = pWord + nCount;
  38.                 break;
  39.             }
  40.         }
  41.     }
  42. }

如果允许进行预处理,我们可以在一个预先计算好的结构中执行二分查找,该结构中包含按标识排序的(标识,单词)对。
2. 给定包含4300 000 000 个32位整数的顺序文件,如何找出一个出现至少两次的整数?
 方法一:
二分搜索通过递归搜索包含半数以上整数的子区间来查找至少出现两次的单词。因为4300000000  > 2^32,所以必定存在重复的整数,搜索范围从[0, 2^32)开始,中间值mid为2^31,若区间[0, 2^31)内的整数个数大于2^31个,则调整搜索区间为[0, 2^31),反之则调整搜索区间为[2^31, 2^32),然后再对整个文件再遍历一遍,直到得到最后的结果。这样一共会有log2(n)次的搜索,每次遍历n个整数(每次都是完全遍历),总体的复杂度为o(nlog2(n))。
 

  1. #include <iostream>
  2. using namespace std;
  3. int pow2(int n)   //求2的n次幂
  4. {
  5.     int i;
  6.     int r = 1;
  7.     for (i = 0; i < n; i++)
  8.     {
  9.         r *=2;
  10.     }
  11.     return r;
  12. }
  13. int _tmain(int argc, _TCHAR* argv[])
  14. {
  15.     int arr[] = {4,2,5,1,6,3,8,0,7,6,11,12,14,9,15,10,13};
  16.     int len = sizeof(arr) / sizeof(int);
  17.     int nCount = 0;
  18.     int bit = 4;
  19.     int low = 0;
  20.     int high = pow2(bit);
  21.     int mid = (low +high) / 2;
  22.     int i;
  23.     while (low <= high )
  24.     {
  25.         mid = (low + high) / 2;  //取中间值
  26.         nCount = 0;
  27.         for (i = 0; i < len; i++)    //计数[low, mid)范围内整数的个数
  28.         {
  29.             if (arr[i] < mid && arr[i] >= low)
  30.             {
  31.                 ++nCount;
  32.             }
  33.         }  //end for
  34.         if (nCount == 0)     //若nCount为0,则mid即为重复的整数
  35.         {
  36.             cout << mid<<endl;
  37.             break;
  38.         }
  39.         else
  40.         {
  41.             if (nCount > (mid – low))  //若大于mid与low的差值,
  42.             {                          //表明重复的整数落在区间[low, mid)
  43.                 high = mid;        //缩小区间
  44.             }
  45.             else
  46.             {
  47.                 low = mid;
  48.             }  //end if
  49.         } //end if () else()
  50.     }  //end while
  51. }

 
   方法二:
 

  1. #include <iostream>
  2. #include <algorithm>
  3. using namespace std;
  4. int _tmain(int argc, _TCHAR* argv[])
  5. {
  6.     int arr[] = {4,2,5,1,7,3,8,0,7,6,11,12,14,9,15,10,13};
  7.     int len = sizeof(arr) / sizeof(int);
  8.     sort(arr, arr + len);   //先进行排序
  9.     int i;
  10.     int increase = arr[0];
  11.     for (i = 0; i < len; i++)
  12.     {
  13.         if (arr[i] > (i + increase))
  14.         {
  15.             increase += (arr[i] – i – increase);
  16.             continue;
  17.         }
  18.         if (arr[i] < (i + increase))
  19.         {
  20.             cout << arr[i] << endl;
  21.             break;
  22.         }
  23.     }
  24. }

3. 前面涉及了两个需要精巧代码来实现的向量旋转算法,将其分别作为独立的程序实现。在每个程序中,i和n的最大公约数如何实现?
采用辗转相除法求两个整数的最大公约数。
 

  1. int gcd(int a, int b)
  2. {
  3.     int temp;
  4.     if (a < b)  //使a始终为最大数
  5.     {
  6.         temp = a;
  7.         a = b;
  8.         b = temp;
  9.     }
  10.     while (b != 0)
  11.     {
  12.         temp = a % b;
  13.         a = b;
  14.         b = temp;
  15.     }
  16.     return a;
  17. }

 
 
方法一:海豚算法
 

  1. void Shifting(char * pArry, int rotdistance, int len)
  2. {
  3.     int i, j;
  4.     char temp;
  5.     int igcd = gcd(rotdistance, len);
  6.     for (i = 0; i < igcd; i++)
  7.     {
  8.         temp = pArry[i];
  9.         j = i;
  10.         for (; 😉
  11.         {
  12.             int k = j + rotdistance;
  13.             k %= len;
  14.             if ( k == i)
  15.             {
  16.                 break;
  17.             }
  18.             pArry[j] = pArry[k];
  19.             j = k;
  20.         }
  21.         pArry[j] = temp;
  22.     }
  23. }

方法二:块交换算法
 

  1. #include <iostream>
  2. using namespace std;
  3. //交换pArry[a…a+m-1]和pArry[b…b+m-1]
  4. void myswap(char *pArry, int a, int b, int m)
  5. {
  6.     char temp;
  7.     for (int i = 0; i < m; i++)
  8.     {
  9.         temp = pArry[a + i];
  10.         pArry[a + i] = pArry[b + i];
  11.         pArry[b + i] = temp;
  12.     }
  13. }
  14. void Shifting(char * pArry, int rotdistance, int len)
  15. {
  16.     if (rotdistance == 0 || rotdistance == len)
  17.     {
  18.         return;
  19.     }
  20.     int i, j, p;
  21.     i = p = rotdistance;
  22.     j = len – p;
  23.     while (i != j)
  24.     {
  25.         if (i > j)
  26.         {
  27.             myswap(pArry, p – i, p, j);
  28.             i -= j;
  29.         }
  30.         else
  31.         {
  32.             myswap(pArry, p – i, p + j – i, i);
  33.             j -= i;
  34.         }
  35.     }
  36.     myswap(pArry, p – i, p, i);
  37. }
  38. int _tmain(int argc, _TCHAR* argv[])
  39. {
  40.     char arry[] = “abcdefghijklmn”;
  41.     int len = strlen(arry);
  42.     Shifting(arry, 10, len);
  43.     return 0;
  44. }

方法三:求逆算法
根据矩阵的转置理论,对于矩阵AB,要得到BA,则分别求A和B的转置A’, B’,然后对(A’B’)转置,即(A’B’)’ = BA。同理,可以得到另一种一维向量向左旋转的算法。将要被旋转的向量x看做两部分ab,这里a代表x中的前rotdistance个元素。首先对a部分进行反转,再对b部分进行反转,最后对整个向量x进行反转即可。
对于字符串“abcdefgh”, rotdistance = 3, len = 8:
reverse(1, rotdistance);          //cbadefgh
reverse(rotdistance+1, len);  //cbahgfed
reverse(1, len);                       //defghabc
 

  1. #include <iostream>
  2. using namespace std;
  3. //对字符串中第i个字符到第j个字符进行反转,i、j>=1
  4. void MyReverse(char * pArry, int i, int j)
  5. {
  6.     int front = i;
  7.     int tail = j;
  8.     char temp;
  9.     while (front != tail && front < tail)
  10.     {
  11.         temp = pArry[front – 1];
  12.         pArry[front – 1] = pArry[tail – 1];
  13.         pArry[tail – 1] = temp;
  14.         ++front;
  15.         –tail;
  16.     }
  17. }
  18. //将字符串左旋转rotdistance个字符
  19. void Shifting(char * pArry, int rotdistance, int len)
  20. {
  21.     if (rotdistance == 0 || rotdistance == len)
  22.     {
  23.         return;
  24.     }
  25.     MyReverse(pArry, 1, rotdistance);
  26.     MyReverse(pArry, rotdistance + 1, len);
  27.     MyReverse(pArry, 1, len);
  28. }
  29. int _tmain(int argc, _TCHAR* argv[])
  30. {
  31.     char arry[] = “abcdefgh”;
  32.     int len = strlen(arry);
  33.     Shifting(arry, 5, len);
  34.     cout << arry << endl;
  35.     return 0;
  36. }

 
5. 向量旋转函数将向量ab变为ba。如何将向量abc变成cba?(这个交换非相邻内存块的问题进行了建模)
可以将bc看做一个整体,然后运用向量旋转算法,得到bca。然后对bc运用向量旋转算法,得到cb。最后变换后的向量为即cba.
 

  1. //交换pArry[a…a+m-1]和pArry[b…b+m-1]
  2. void myswap(char *pArry, int a, int b, int m)
  3. {
  4.     char temp;
  5.     for (int i = 0; i < m; i++)
  6.     {
  7.         temp = pArry[a + i];
  8.         pArry[a + i] = pArry[b + i];
  9.         pArry[b + i] = temp;
  10.     }
  11. }

 
 

  1. //对向量pArry中起始于ibegainPos位置的irotdistance-ibegainPos个元素
  2. //与起始于ibegainPos+irotdistance位置到位置iendPos之前的元素进行交换
  3. void SuccessiveSwap(char * pArry, int ibegainPos, int irotdistance, int iendPos)
  4. {
  5.     int i, j;
  6.     i = irotdistance – ibegainPos;
  7.     j = iendPos – irotdistance;
  8.     while (i != j)
  9.     {
  10.         if (i > j)
  11.         {
  12.             myswap(pArry, irotdistance – i, irotdistance, j);
  13.             i -= j;
  14.         }
  15.         else
  16.         {
  17.             myswap(pArry, irotdistance – i, irotdistance + j – i, i);
  18.             j -= i;
  19.         }
  20.     }
  21.     myswap(pArry, irotdistance – i, irotdistance, i);
  22. }

6. 如何实现一个以名字的按键编码为参数,并返回所有可能的匹配名字的函数
用按键编码标识每一个名字,并根据标识排序,然后顺序读取排序后的文件并输出具有不同名字的相同标识。为了检索出给定按钮编码的名字,可以使用一种包含编码标识和其他数据的结构。然后对该结构排序,使用二分搜索查询按键编码。
7. 转置一个存储在磁带上的4000×4000的矩阵(每条记录的格式相同,为数十个字节)。如何将运行的时间减少到半个小时?
给每条记录插入列号和行号,然后调用系统的磁带排序程序先按列排序再按行排序,最后使用另一个程序删除列号和行号。
8. 给定一个n元实数集合、一个实数t和一个整数k,如何快速确定是否存在一个k元子集,其元素之和不超过t?
对n元实数集合先进行排序,然后计算前k个元素的和既可以确定是否存在这样一个子集。若采用快速排序,时间复杂度为nlog10(n)。
9. 顺序搜素和二分搜索代表了搜索时间和预处理时间之间的折中。处理一个n元表格时,需要执行多少次二分搜索才能弥补对表进行排序所消耗的预处理时间?
对于顺序搜索,搜索k次的时间复杂度为O(kn);若采用二分搜索则需要先排序,则二分搜索的时间复杂度为O(nlog10(n)+log2(n))
变位词程序的实现
 

  1. //对从文件中读入的每个单词调用qsort库函数排序,输出到新的文件中
  2. void mysign(FILE * pFile1, FILE * pFile2)
  3. {
  4.     char word[20];
  5.     char sig[20];
  6.     pFile1 = fopen(“..file1.txt”, “r”);
  7.     if ( NULL == pFile1)
  8.     {
  9.         cout << “Open file1 error!” << endl;
  10.         return ;
  11.     }
  12.     pFile2 = fopen(“..file2.txt”, “w”);
  13.     if (NULL == pFile2)
  14.     {
  15.         cout << “Open file2 error!” << endl;
  16.         return ;
  17.     }
  18.     while (!feof(pFile1))
  19.     {
  20.         memset(word, ‘’, 20);
  21.         memset(sig, ‘’, 20);
  22.         fscanf(pFile1, “%s”, word);
  23.         strncpy(sig, word, strlen(word));
  24.         qsort(sig, strlen(sig), sizeof(char), charcomp);
  25.         fprintf(pFile2, “%s   %sn”, sig, word);
  26.     }
  27.     fclose(pFile1);
  28.     fclose(pFile2);
  29. }


 
 
使用sort程序将具有相同标识的单词归拢到一起,形成一个新的文件。最后调用squash()函数将具有相同变位词的单词在同一行输出。
 

  1. //将具有相同变位词的单词在同一行输出
  2. void squash()
  3. {
  4.     FILE * pFile3 = fopen(“..file3.txt”, “r”);
  5.     if ( NULL == pFile3)
  6.     {
  7.         cout << “Open file3 error!” << endl;
  8.         return ;
  9.     }
  10.     FILE * pFile4 = fopen(“..file4.txt”, “w”);
  11.     if (NULL == pFile4)
  12.     {
  13.         cout << “Open file4 error!” << endl;
  14.     }
  15.     char word[20];
  16.     char sig[20];
  17.     char oldsig[20];
  18.     int linenum = 0;
  19.     memset(oldsig, ‘’, 20);
  20.     while (!feof(pFile3))
  21.     {
  22.         memset(word, ‘’, 20);
  23.         memset(sig, ‘’, 20);
  24.         fscanf(pFile3, “%s %s”, sig, word);
  25.         if (strncmp(sig, oldsig, strlen(sig)) != 0 )
  26.         {
  27.             fprintf(pFile4, “n”);
  28.         }
  29.         strncpy(oldsig, sig, strlen(sig));
  30.         fprintf(pFile4, “%s “, word);
  31.     }
  32.     fclose(pFile3);
  33.     fclose(pFile4);
  34. }