原文查看:
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(); } } }