原文查看:
http://www.ibaiyang.org/2013/01/06/suffix-tree-introduction/
看过非常多的不靠谱suffix tree介绍后,本文是我在网上发现至今最好的一篇,通过三个规则讲述了整棵后缀树的构建过程,图形结合,非常容易理解,并且本文尊重原作者Ukkonen的论文术语,清楚的讲解了出现在suffix tree中的每一个概念,花时3个小时翻译之,共勉,部分有修改和抛弃。
正文如下:
接下来我将通过一个简单的字符串(不包含重复的字符)来试着分析Ukkonen算法,接着来讲述完整的算法框架。
首先,一点简单的事前描述
1. 我们构建的是一个简单的类似搜索字典类(search trie)结构,所以存在一个根节点(root node)。树的边(edges)指向一个新的节点,直到叶节点。
2. 但是,不同于搜索字典类(search trie),边标签(edge label)不是单个字符,相反,每一个边被标记为一对整数[from, to]。这一对整数是输入字符串的索引(index)。这样,每一个边记录了任意长度的子字符(substring),但是只需要O(1)空间复杂度(一对整数索引)。
基本约定
下面我将用一个没有重复字符的字符串来说明如何创建一颗后缀树(suffix tree):
abc
本算法将从字符串的左边向右边一步一步的执行。每一步处理输入字符串的一个字符,并且每一步抑或涉及不止一种的操作,但是所有的操作数和是O(n)时间复杂度的。
好,我们现在将字符串左边的a插入到后缀树,并且将此边标记为[0, #],它的意思是此边代表了从索引0开始,在#索引结束的子字符串(我使用符号#表示当前结束索引,现在的值是1,恰好在a位置后面)。
所以,我们有初始化后的后缀树:
其意思是:
现在我们处理索引2,字符b。我们每步的目的是将所有后缀(suffixes)的结束索引更新当前的索引。我们可以这样做:
1. 拓展存在的a边,使其成为ab;
2. 为b插入一条新边。
然后变成这样:
其意思是:
我们观察到了二点:
接下来,我们继续自增#索引,现在我们需要插入字符c了。我们将c插入到后缀树中的每一条边,然后在为后缀c插入一条新边。
它们像下面:
其意思是:
我们注意到:
第一次拓展:简单的重复字符串
上面的算法工作的非常正确,接下来我们来看看更加复杂的字符串:
abcabxabcd
步骤1至3:正如之前的例子:
步骤4:我们自增#到索引4。这将自动的更新所有已存在的边:
本人用VC写的简单的、界面漂亮的MP3播放器。界面采用MFC框架,解码核心采用现成的COM组件,精美UI采用皮肤控件。内含程序+源码,VS2010编写。下载地址为:
点我下载
废话不说,先上几张图片:
虽然功能简单但比较实用、简洁,可以最小化到托盘,自动按顺序播放下一曲。
自己写的代码也就300行不到,注释很清楚,大家可以下载源码看。还有很多不足多多包涵。注意程序的运行离不开Mp3play.ocx skinh.she SkinHu.dll这三个文件,应该和exe放到同一目录下,Mp3play.ocx是用于解码的COM组件,skinh.she SkinHu.dll就是皮肤资源和皮肤控件啦。
package dislab.gossipdog.wifi.adhoc;
import java.io.BufferedReader;
import java.io.FileReader;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.DhcpInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.text.format.Formatter;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class AdHocActivity extends Activity {
private final String TAG = "WifiSoftAP";
public static final String WIFI_AP_STATE_CHANGED_ACTION =
"android.net.wifi.WIFI_AP_STATE_CHANGED";
public static final int WIFI_AP_STATE_DISABLING = 0;
public static final int WIFI_AP_STATE_DISABLED = 1;
public static final int WIFI_AP_STATE_ENABLING = 2;
public static final int WIFI_AP_STATE_ENABLED = 3;
public static final int WIFI_AP_STATE_FAILED = 4;
TextView result;
WifiManager wifiManager;
WifiReceiver receiverWifi;
List<ScanResult> wifiList;
//����l���б�
private List<WifiConfiguration> wifiConfiguration;
StringBuilder resultList = new StringBuilder();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//setTitle("");
result = (TextView) findViewById(R.id.result);
wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Button btnOpenAP = (Button)this.findViewById(R.id.btnOpenAP);
btnOpenAP.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (!isApEnabled()){
setWifiApEnabled(true);
}
}
});
Button btnCloseAP = (Button)this.findViewById(R.id.btnCloseAP);
btnCloseAP.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (isApEnabled()){
setWifiApEnabled(false);
}
}
});
Button btnScan = (Button)this.findViewById(R.id.btnScan);
btnScan.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
StartScan();
}
});
Button btnConnectAP = (Button)this.findViewById(R.id.btnConnectAP);
btnConnectAP.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
connectAP();
}
});
Button btnGetConnectedIP = (Button)this.findViewById(R.id.btnGetConnectedIP);
btnGetConnectedIP.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
ArrayList<String> connectedIP = getConnectedIP();
resultList = new StringBuilder();
for(String ip : connectedIP){
resultList.append(ip);
resultList.append("\n");
}
result.setText(resultList);
}
});
findViewById(R.id.btnGetOwmId).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.d("ZSM", getLocalIpAddress());
WifiInfo wifiinfo = wifiManager.getConnectionInfo();
Log.v("getBSSID", wifiinfo.getBSSID() + "");
Log.v("getHiddenSSID", wifiinfo.getBSSID() + "");
Log.v("getIpAddress", Formatter.formatIpAddress(wifiinfo.getIpAddress()) + "");
Log.v("getLinkSpeed", Formatter.formatIpAddress(wifiinfo.getLinkSpeed()) + "");
Log.v("getMacAddress", wifiinfo.getMacAddress() + "");
Log.v("getNetworkId", Formatter.formatIpAddress(wifiinfo.getNetworkId()) + "");
Log.v("getRssi", wifiinfo.getRssi() + "");
Log.v("getSSID", wifiinfo.getSSID() + "");
DhcpInfo dhcpinfo = wifiManager.getDhcpInfo();
Log.v("ipaddr", Formatter.formatIpAddress(dhcpinfo.ipAddress) + "");
Log.v("gatewau", Formatter.formatIpAddress(dhcpinfo.gateway) + "");
Log.v("netmask", Formatter.formatIpAddress(dhcpinfo.netmask) + "");
Log.v("dns1", Formatter.formatIpAddress(dhcpinfo.dns1) + "");
Log.v("dns1", Formatter.formatIpAddress(dhcpinfo.dns2) + "");
Log.v("serverAddress", Formatter.formatIpAddress(dhcpinfo.serverAddress) + "");
Log.d("ZSM", Formatter.formatIpAddress(dhcpinfo.serverAddress));
Log.d("ZSM","ipaddr "+ Formatter.formatIpAddress(dhcpinfo.ipAddress));
}
});
}
//此方法暂不可用
public String getLocalIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf
.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
return inetAddress.getHostAddress().toString();
}
}
}
} catch (SocketException ex) {
Log.e("WifiPreference IpAddress", ex.toString());
}
return null;
}
public String getLocalMacAddress() {
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo info = wifi.getConnectionInfo();
return info.getMacAddress();
}
protected void onPause() {
if (receiverWifi != null)
unregisterReceiver(receiverWifi);
super.onPause();
}
protected void onResume() {
if (receiverWifi != null)
registerReceiver(receiverWifi, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
super.onResume();
}
public void StartScan() {
//��wifi
wifiManager.setWifiEnabled(true);
receiverWifi = new WifiReceiver();
registerReceiver(receiverWifi, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
wifiManager.startScan();
result.setText("\nScaning...\n");
}
public boolean setWifiApEnabled(boolean enabled) {
if (enabled) { // disable WiFi in any case
wifiManager.setWifiEnabled(false);
}
try {
WifiConfiguration apConfig = new WifiConfiguration();
apConfig.SSID = "GossipDog";
apConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
apConfig.preSharedKey = "abcdefgh";
Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);
return (Boolean) method.invoke(wifiManager, apConfig, enabled);
} catch (Exception e) {
Log.e(TAG, "Cannot set WiFi AP state", e);
return false;
}
}
public int getWifiApState() {
try {
Method method = wifiManager.getClass().getMethod("getWifiApState");
return (Integer) method.invoke(wifiManager);
} catch (Exception e) {
Log.e(TAG, "Cannot get WiFi AP state", e);
return WIFI_AP_STATE_FAILED;
}
}
public boolean isApEnabled() {
int state = getWifiApState();
return WIFI_AP_STATE_ENABLING == state || WIFI_AP_STATE_ENABLED == state;
}
//l��GossipDog
public void connectAP() {
WifiConfiguration gossipDog = new WifiConfiguration();
for (WifiConfiguration ap : wifiConfiguration) {
if (ap.SSID == "GossipDog") {
gossipDog = ap;
}
}
if (gossipDog != null) {
gossipDog.preSharedKey = "abcdefgh";
gossipDog.networkId = wifiManager.addNetwork(gossipDog);
wifiManager.enableNetwork(gossipDog.networkId, true);
result.setText("l��AP�ɹ�");
}
}
//获取所有连接到本wifi热点的手机IP地址
private ArrayList<String> getConnectedIP() {
ArrayList<String> connectedIP = new ArrayList<String>();
try {
BufferedReader br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null) {
Log.d("meng", line);
String[] splitted = line.split(" +");
if (splitted != null && splitted.length >= 4) {
String ip = splitted[0];
connectedIP.add(ip);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return connectedIP;
}
class WifiReceiver extends BroadcastReceiver {
public void onReceive(Context c, Intent intent) {
resultList = new StringBuilder();
wifiList = wifiManager.getScanResults();
for (int i = 0; i < wifiList.size(); i++) {
resultList.append(new Integer(i + 1).toString() + ".");
resultList.append((wifiList.get(i)).toString());
resultList.append("\n\n");
}
result.setText(resultList);
//�õ����úõ�����l��
wifiConfiguration = wifiManager.getConfiguredNetworks();
}
}
}