๐Ÿ”ฅ[99ํด๋Ÿฝ ์ฝ”ํ…Œ ์Šคํ„ฐ๋””] 15์ผ์ฐจ TIL - Trie(ํŠธ๋ผ์ด)

HOONSSACยท2024๋…„ 8์›” 5์ผ
1

99Club Coding Test Study

๋ชฉ๋ก ๋ณด๊ธฐ
15/41
post-thumbnail
post-custom-banner

๐Ÿ”ŽTrie

Trie ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ๋ฌธ์ž์—ด์„ ํšจ์œจ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋œ ํŠธ๋ฆฌ ๊ธฐ๋ฐ˜์˜ ์ž๋ฃŒ๊ตฌ์กฐ์ด๋‹ค.

์ฃผ๋กœ ๋ฌธ์ž์—ด ๊ฒ€์ƒ‰, ์ž๋™ ์™„์„ฑ, ์‚ฌ์ „ ๊ตฌํ˜„ ๋“ฑ ๋‹ค์–‘ํ•œ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

๋ฐœ์Œ์ด ์ฒ˜์Œ์—๋Š” 'ํŠธ๋ฆฌ'์˜€์ง€๋งŒ, ํŠธ๋ฆฌ(Tree) ์ž๋ฃŒ๊ตฌ์กฐ์™€ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด 'ํŠธ๋ผ์ด'๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค.

์›ํ•˜๋Š” ์›์†Œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ์—์„œ๋Š” ์›์†Œ๋ฅผ ์ฐพ๋Š” ๋ฐ O(logN)O(logN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค.
ํ•˜์ง€๋งŒ ๋ฌธ์ž์—ด์˜ ๊ฒฝ์šฐ ๋‘ ๋ฌธ์ž์—ด์„ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌธ์ž์—ด์˜ ๊ธธ์ด ๋งŒํผ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์—, ์›ํ•˜๋Š” ๋ฌธ์ž์—ด์„ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ๋Š” O(MlogN)O(MlogN)์˜ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ์ž์—ด ํŠนํ™” ์ž๋ฃŒ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋กœ ์ด ํŠธ๋ผ์ด(Trie)์ด๋‹ค.

๐Ÿ› ๏ธ์ž‘๋™ ์›๋ฆฌ

๋‹ค์Œ ๊ทธ๋ฆผ์€ ๋ฌธ์ž์—ด ์ง‘ํ•ฉ {"apple", "april", "busy", "beer", "best"}๋ฅผ ํŠธ๋ผ์ด๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๋‹ค.

ํŠธ๋ผ์ด๋Š” ํ•œ ๋ฌธ์ž์—ด์—์„œ ๋‹ค์Œ์— ๋‚˜์˜ค๋Š” ๋ฌธ์ž๊ฐ€ ํ˜„์žฌ ๋ฌธ์ž์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ๋˜๊ณ , ํŒŒ๋ž€์ƒ‰์œผ๋กœ ๋‚˜ํƒ€๋‚ธ ๋ฆฌํ”„ ๋…ธ๋“œ๋Š” ๋ฌธ์ž์—ด์˜ ๋์„ ์˜๋ฏธํ•œ๋‹ค.

ํŠธ๋ผ์ด๋Š” ๋ฌธ์ž์—ด์„ ํƒ์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ์ด๋ฏ€๋กœ ๋ฌธ์ž์—ด ํƒ์ƒ‰์„ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ ๊ธ€์ž์— ํ•ด๋‹นํ•˜๋Š” ๋…ธ๋“œ๋ฅผ ํƒ€๊ณ  ๋”ฐ๋ผ๊ฐ€๋ฉด ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด "april"์„ ์ฐพ๋Š”๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.
a โ†’ ap โ†’ apr โ†’ apri โ†’ april์˜ ์ˆœ์„œ๋กœ ํƒ์ƒ‰๋˜๋ฏ€๋กœ "april"์˜ ๋ชจ๋“  ์ ‘๋‘์‚ฌ๋“ค์ด ๋‹ค ๊ตฌํ•ด์ง€๊ฒŒ ๋œ๋‹ค.

๐Ÿค”์žฅ๋‹จ์ 

์žฅ์ 

  • ๋ฌธ์ž์—ด์„ ๋น ๋ฅด๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฌธ์ž์—ด์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฌธ์ž์—ด์˜ ๊ธธ์ด๋งŒํผ ๋…ธ๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๊ฑฐ๋‚˜, ์ถ”๊ฐ€ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ž์—ด์˜ ์ถ”๊ฐ€์™€ ํƒ์ƒ‰์ด ๋ชจ๋‘ O(M)O(M)๋งŒ์— ๊ฐ€๋Šฅํ•˜๋‹ค.

๋‹จ์ 

  • ํ•„์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ํฌ๋‹ค.
  • ๋ฌธ์ž์—ด์ด ๋ชจ๋‘ ์•ŒํŒŒ๋ฒณ ์†Œ๋ฌธ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด์ง„ ๊ฒฝ์šฐ๋ผ๋„ 1 depth์— a~z๊นŒ์ง€ 26๊ฐœ์˜ ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜๊ฒŒ ๋œ๋‹ค.


๐Ÿ’ป๊ตฌํ˜„

์ž๋ฐ”๋กœ Trie๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ธ Trie์™€ ์ด๋ฅผ ๊ตฌ์„ฑํ•  TrieNode ํด๋ž˜์Šค๊ฐ€ ๊ฐ๊ฐ ํ•„์š”ํ•˜๋‹ค.

TrieNode.java

TrieNode๋Š” ์ž์‹ ๋…ธ๋“œ Map๊ณผ ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ ๋งˆ์ง€๋ง‰ ๊ธ€์ž์ธ์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

public class TrieNode {
	// ์ž์‹ ๋…ธ๋“œ Map
	private Map<Character, TrieNode> childNodes = new HashMap<>();
	// ๋งˆ์ง€๋ง‰ ๊ธ€์ž์ธ์ง€ ์—ฌ๋ถ€
	private boolean isLastChar;
	
}

์ด๋ ‡๊ฒŒ ๋‘ ๋ณ€์ˆ˜๊ฐ€ ํ• ๋‹น๋˜์—ˆ์œผ๋‹ˆ ์ด ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” Getter์™€ Setter๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

childNodes๋Š” Trie์ฐจ์›์—์„œ ์ƒ์„ฑํ•ด ์‚ฝ์ž…ํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, Getter๋งŒ ์ƒ์„ฑํ•ด ์ค€๋‹ค.
isLastChar๋Š” ์ถ”ํ›„ ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•˜๋Š” ๊ณผ์ •์—์„œ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Getter์™€ Setter๋ฅผ ๋‘˜ ๋‹ค ์ƒ์„ฑํ•ด ์ค€๋‹ค.

public class TrieNode {
	// ์ž์‹ ๋…ธ๋“œ Map
	private Map<Character, TrieNode> childNodes = new HashMap<>();
	// ๋งˆ์ง€๋ง‰ ๊ธ€์ž์ธ์ง€ ์—ฌ๋ถ€
	private boolean isLastChar;
	
	// ์ž์‹ ๋…ธ๋“œ ๋งต Getter
	Map<Character, TrieNode> getChildNodes() {
		return this.childNodes;
	}
	// ๋งˆ์ง€๋ง‰ ๊ธ€์ž์ธ์ง€ ์—ฌ๋ถ€ Getter
	boolean isLastChar() {
		return this.isLastChar;
	}
	// ๋งˆ์ง€๋ง‰ ๊ธ€์ž์ธ์ง€ ์—ฌ๋ถ€ Setter
	void setIsLastChar(boolean isLastChar) {
		this.isLastChar = isLastChar;
	}
}

Trie.java

Trie๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋นˆ ๋ฌธ์ž์—ด์„ ๊ฐ€์ง€๋Š” ๋ฃจํŠธ ๋…ธ๋“œ๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

public class Trie {
	private TrieNode rootNode; // ๋ฃจํŠธ ๋…ธ๋“œ
}

์ž์‹ ๋…ธ๋“œ๋Š” ๊ณง ๋‚˜์˜ฌ insert๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•จ์œผ๋กœ์จ ์ƒ์„ฑ๋  ๊ฒƒ์ด๋‹ค.

์šฐ์„ , Trie๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด rootNode๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋„๋ก ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด rootNode๋ฅผ ์ƒ์„ฑํ•ด ์ค€๋‹ค.

public class Trie {
	private TrieNode rootNode; // ๋ฃจํŠธ ๋…ธ๋“œ
    
    // ์ƒ์„ฑ์ž
    Trie() {
    	rootNode = new TrieNode();
    }   
}

insert

insert ๋ฉ”์„œ๋“œ์—์„œ๋Š” ์ž…๋ ฅ๋ฐ›์€ ๋‹จ์–ด์˜ ๊ฐ ์•ŒํŒŒ๋ฒณ์„ ๊ณ„์ธต ๊ตฌ์กฐ์˜ ์ž์‹ ๋…ธ๋“œ๋กœ ๋งŒ๋“ค์–ด ๋„ฃ๋Š” ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค.
์ด ๋•Œ, ์ด๋ฏธ ๊ฐ™์€ ์•ŒํŒŒ๋ฒณ์ด ์กด์žฌํ•˜๋ฉด ๊ณตํ†ต ์ ‘๋‘์–ด ๋ถ€๋ถ„๊นŒ์ง€๋Š” ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.
์ฆ‰, ํ•ด๋‹น ๊ณ„์ธต ๋ฌธ์ž์˜ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ๋งŒ ์ž์‹ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, "apple"์ด ๋“ค์–ด์žˆ๋Š” Trie์— "april"์„ ๋„ฃ์„ ๋•Œ, "ap"๋Š” ์ค‘๋ณต์ด๋ฏ€๋กœ "a โ†’ p"๋…ธ๋“œ ์•„๋ž˜ "โ†’ r โ†’ i โ†’ l"๋งŒ ์ถ”๊ฐ€๋กœ ์ž์‹ ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ๋ฉด ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฆฌํ”„ ๋…ธ๋“œ์—์„œ๋Š” ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋ผ๋Š” ๊ฒƒ์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด setIsLastChar(true)๋ฅผ ํ•ด์ค€๋‹ค.

void insert(String word) {
	TrieNode thisNode = this.rootNode;

	for (int i = 0; i < word.length(); i++) {
		thisNode = thisNode.getChildNodes().computeIfAbsent(word.charAt(i), c -> new TrieNode());
	}
	thisNode.setIsLastChar(true);
}

contains

ํŠน์ • ๋‹จ์–ด๊ฐ€ Trie์— ์กด์žฌํ•˜๋Š” ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ ์กฐ๊ฑด์„ ๋งŒ์กฑ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

  • ๋ฃจํŠธ ๋…ธ๋“œ๋ถ€ํ„ฐ ์ˆœ์„œ๋Œ€๋กœ ์•ŒํŒŒ๋ฒณ์ด ์ผ์น˜ํ•˜๋Š” ์ž์‹ ๋…ธ๋“œ๋“ค์ด ์กด์žฌํ•  ๊ฒƒ

  • ํ•ด๋‹น ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๊ธ€์ž์— ํ•ด๋‹นํ•˜๋Š” ๋…ธ๋“œ์˜ isLastChar๊ฐ€ true์ผ ๊ฒƒ

boolean contains(String word) {
	TrieNode thisNode = this.rootNode;

	for (int i = 0; i < word.length(); i++) {
		char character = word.charAt(i);
		TrieNode node = thisNode.getChildNodes().get(character);

		if (node == null)
			return false;

		thisNode = node;
	}

	return thisNode.isLastChar();
}

delete

๋งˆ์ง€๋ง‰์œผ๋กœ ๋‹จ์–ด๋ฅผ ์‚ญ์ œํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.
์ผ๋‹จ, contains ๋ฉ”์„œ๋“œ์ฒ˜๋Ÿผ ์ฃผ์–ด์ง„ ๋‹จ์–ด๋ฅผ ์ฐพ์•„ ํ•˜์œ„ ๋…ธ๋“œ๋กœ ๋‹จ์–ด ๊ธธ์ด๋งŒํผ ๋‚ด๋ ค๊ฐ„๋‹ค.
์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์€ ๋…ธ๋“œ๋“ค์ด ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ํ•˜์œ„ ๋…ธ๋“œ๋กœ ๋‚ด๋ ค๊ฐ€๋ฉฐ ์‚ญ์ œ ๋Œ€์ƒ ๋‹จ์–ด๋ฅผ ํƒ์ƒ‰ํ•˜๊ณ , ๋‹ค์‹œ ์˜ฌ๋ผ์˜ค๋ฉฐ ์‚ญ์ œํ•˜๋Š” ๊ณผ์ •์ด ๊ตฌํ˜„๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

delete ๋ฉ”์„œ๋“œ๋Š” ์•„๋ž˜์˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.

  • ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค.
  • ์‚ญ์ œ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ์ฒซ ๋…ธ๋“œ๋Š” isLastChar์ด true์—ฌ์•ผ ํ•œ๋‹ค.
  • ์‚ญ์ œ๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ์ค‘์—๋Š” isLastChar์ด false์—ฌ์•ผ ํ•œ๋‹ค.
void delete(String word) {
	delete(this.rootNode, word, 0); 
}
	
private void delete(TrieNode thisNode, String word, int index) {
		
	char character = word.charAt(index);
            
	TrieNode childNode = thisNode.getChildNodes().get(character);
	index++;
    
	if(index == word.length()) {
		childNode.setIsLastChar(false);

		// ์‚ญ์ œ ๋Œ€์ƒ ์–ธ์–ด์˜ ์ œ์ผ ๋์œผ๋กœ์จ ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด(์ด ๋‹จ์–ด๋ฅผ ํฌํ•จํ•˜๋Š” ๋” ๊ธด ๋‹จ์–ด๊ฐ€ ์—†์œผ๋ฉด) ์‚ญ์ œ ์‹œ์ž‘
		if (childNode.getChildNodes().isEmpty())
			thisNode.getChildNodes().remove(character);
	}
    else {
		delete(childNode, word, index);
		// ์‚ญ์ œ ์ค‘, ์ž์‹ ๋…ธ๋“œ๊ฐ€ ์—†๊ณ  ํ˜„์žฌ ๋…ธ๋“œ๋กœ ๋๋‚˜๋Š” ๋‹ค๋ฅธ ๋‹จ์–ด๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์ด ๋…ธ๋“œ ์‚ญ์ œ
		if(!childNode.isLastChar() && childNode.getChildNodes().isEmpty())
			thisNode.getChildNodes().remove(character);
	}
}

๐Ÿ’ปReference
[JAVA/์ž๋ฃŒ๊ตฌ์กฐ] ํŠธ๋ผ์ด(Trie) ๊ฐœ๋…, ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ

profile
ํ›ˆ์‹น์˜ ๊ฐœ๋ฐœ์—ฌํ–‰
post-custom-banner

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2024๋…„ 8์›” 5์ผ

์–ด๋ ต๊ตฌ๋จผ...๊ทธ๋ž˜๋„ ํŠธ๋ผ์ดํ•ด๋ณด์ž๊ณ ~!๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ‘Š๐Ÿ‘Š

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ