数据结构之字典树 Java实现

数据结构之字典树 Java实现

public class Tire {

	private Tire[] children;

	private boolean isLeaf;

	private long passCount;

	private long leafCount;

	public static final Tire INSTANCE = new Tire();

	private Tire() {
		children = new Tire[26];
		isLeaf = false;
	}

	private Tire[] getChildren() {
		return children;
	}

	private void incPassCount() {
		passCount++;
	}

	private void incLeafCount() {
		leafCount++;
	}

	private boolean noPass(Tire node) {
		return node.passCount == 0;
	}

	public void insert(String word) {
		if (word == null || word.length() == 0 || search(word)) return;
		Tire node = this;
		for (int i = 0; i < word.length(); i++) {
			int index = word.charAt(i) - 'a';
			Tire[] children = node.getChildren();
			if (children[index] == null) {
				children[index] = new Tire();
			}
			node = children[index];
			node.incPassCount();
		}
		node.isLeaf = true;
		node.incLeafCount();
	}

	public boolean search(String word) {
		if (word == null || word.length() == 0) return false;
		return dfsSearch(this, 0, word);
	}

	private boolean dfsSearch(Tire node, int index, String word) {
		if (index == word.length()) {
			return node.isLeaf;
		}
		int ch = word.charAt(index) - 'a';
		Tire[] children = node.getChildren();
		if (children[ch] != null && !noPass(children[ch]) && dfsSearch(children[ch], index + 1, word)) {
			return true;
		}
		return false;
	}

	public boolean preSearch(String word) {
		if (word == null || word.length() == 0) return false;
		Tire node = this;
		for (int i = 0; i < word.length(); i++) {
			int ch = word.charAt(i) - 'a';
			Tire[] children = node.getChildren();
			if (children[ch] == null || noPass(children[ch])) return false;
			node = children[ch];
		}
		return true;
	}

	private Tire preSearchNode(String word) {
		if (word == null || word.length() == 0) return null;
		Tire node = this;
		for (int i = 0; i < word.length(); i++) {
			int ch = word.charAt(i) - 'a';
			Tire[] children = node.getChildren();
			if (children[ch] == null || noPass(children[ch])) return null;
			node = children[ch];
		}
		return node;
	}

	public List<String> getAllPreWord(String word) {
		Tire tire = preSearchNode(word);
		if (tire == null || noPass(tire)) return new ArrayList<>();
		return dfsAllPreWord(tire, word);
	}

	public List<String> getAllWord(){
		return dfsAllPreWord(this,"");
	}

	private List<String> dfsAllPreWord(Tire node, String word) {
		List<String> res = new ArrayList<>();
		if (node.isLeaf) {
			if (node.passCount == 1) {
				return Arrays.asList(word);
			} else {
				res.addAll(Arrays.asList(word));
			}
		}
		Tire[] children = node.getChildren();
		for (int i = 0; i < children.length; i++) {
			if (children[i] != null && !noPass(children[i])) {
				char ch = (char) ('a' + i);
				res.addAll(dfsAllPreWord(children[i], word + ch));
			}
		}
		if (res.isEmpty()) {
			return Arrays.asList(word);
		}
		return res;
	}

	public void remove(String word) {
		if (search(word)) {
			dfsRemove(this, 0, word);
		}
	}

	private void dfsRemove(Tire node, int index, String word) {
		if (index == word.length()) {
			node.leafCount--;
			if (node.leafCount == 0) {
				node.isLeaf = false;
			}
			return;
		}
		int ch = word.charAt(index) - 'a';
		Tire[] children = node.getChildren();
		children[ch].passCount--;
		dfsRemove(children[ch], index + 1, word);
	}

	public static void main(String[] args) {
		Tire tire = new Tire();
		tire.insert("at");
		tire.insert("at");
		tire.insert("and");
		tire.insert("ac");
		tire.insert("ace");
		tire.insert("bc");
		tire.insert("an");
		tire.insert("add");
		tire.insert("adddd");
		tire.insert("bat");
		tire.insert("abc");
		tire.remove("at");
		System.out.println(tire.search("at"));
		System.out.println(tire.getAllPreWord("an"));
		System.out.println(tire.getAllWord());
	}
}
/* * 基于散列表实现的(无序)词典结构 * 采用分离链策略解决冲突 */ package dsa; public class Dictionary_HashTable implements Dictionary { private Dictionary[] A;//桶数组,每个桶本身也是一个(基于列表实现的)词典结构 private int N;//散列表长 private final double maxLemda = 0.75;//装填因子上限 private int size;//词典结构的规模 private EqualityTester T;//判等器 //默认构造方法 public Dictionary_HashTable() { this(0, new EqualityTesterDefault()); } //构造方法 public Dictionary_HashTable(int n, EqualityTester t) { T = t; N = p(n);//桶数组容量取为不小于n的最小素数 A = new Dictionary[N]; for (int i=0; i<N; i++) A[i] = new Dictionary_DLNode(T); size = 0; } /***************************** 辅助方法 *****************************/ //散列定址函数(采用模余法) private int h(Object key) { return key.hashCode() % N; } //判断n是否为素数 private static boolean prime(int n) { for (int i=3; i<1+Math.sqrt(n); i++) if (n/i*i == n) return false; return true; } //取不小于n的最小素数 private static int p(int n) { if (3>n) n = 3; n = n | 1;//奇数化 while (!prime(n)) n += 2; return n; } /***************************** ADT方法 *****************************/ //查询词典结构当前的规模 public int getSize() { return size; } //判断词典结构是否为空 public boolean isEmpty() { return 0==size; } //若词典中存在以key为关键码的条目,则返回其中的一个条目;否则,返回null public Entry find(Object key) { return A[h(key)].find(key); } //返回由关键码为key的条目组成的迭代器 public Iterator findAll(Object key) { return A[h(key)].findAll(key); } //插入条目(key, value),并返回该条目 public Entry insert(Object key, Object value) { Entry entry = A[h(key)].insert(key, value);//将新条目插至桶A[h(key)]对应的子词典 size ++;//更新规模记录 if (size > N * maxLemda) rehash();//若装填因子过大,则重散列 return entry;//返回null标志 } //若词典中存在以key为关键码的条目,则将其摘除并返回;否则,返回null public Entry remove(Object key) { Entry oldEntry = A[h(key)].remove(key); if (null!=oldEntry) size--; return oldEntry; } //返回词典中所有条目的一个迭代器 public Iterator entries() { List L = new List_DLNode(); for (int i=0; i<N; i++) { Iterator it = A[i].entries(); while (it.hasNext()) L.insertLast(it.getNext()); } return new IteratorElement(L); } //重散列 private void rehash() { Iterator it = this.entries(); N = p(N<<1); A = new Dictionary[N];//桶数组容量至少加倍 for (int i=0; i<N; i++) A[i] = new Dictionary_DLNode(T);//为每个桶分配一个子词典 while (it.hasNext()) {//将其对应的词典结构中的 Entry e = (Entry)it.getNext();//各条目逐一取出,将其 Object k = e.getKey();//关键码和 Object v = e.getValue();//数据对象 A[h(k)].insert(k, v);//整合为新的条目,插入对应的子词典中 } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值