Data update

This commit is contained in:
Ingy döt Net 2024-03-06 22:25:12 -08:00
parent ed705008a8
commit 0df55f9f24
2196 changed files with 32999 additions and 3075 deletions

View file

@ -12,5 +12,6 @@ Construct an eertree for the string "eertree", then output all sub-palindromes b
*   Wikipedia entry:   [https://en.wikipedia.org/wiki/Trie trie].
*   Wikipedia entry:   [https://en.wikipedia.org/wiki/Suffix_tree suffix tree]
*   [https://arxiv.org/abs/1506.04862 Cornell University Library, Computer Science, Data Structures and Algorithms ───► EERTREE: An Efficient Data Structure for Processing Palindromes in Strings].
*EERTREE: An efficient data structure for processing palindromes in strings[https://www.sciencedirect.com/science/article/pii/S0195669817301294]
<br><br>

View file

@ -0,0 +1,108 @@
class Node {
constructor(len, suffix, id, level) {
this.edges = new Map(); // edges <Character, Node>
this.link = suffix; // Suffix link points to another node
this.length = len; // Length of the palindrome represented by this node
this.palindrome = "";
this.parent = null;
}
}
class Eertree {
constructor() {
this.imaginary = new Node(-1, null, this.count++, 1); // also called odd length root node
this.empty = new Node(0, this.imaginary, this.count++, 2); // also called even length root node
this.maxSuffixOfT = this.empty; // this is the current node we are on also the maximum Suffix of tree T
this.s = ""; // String processed by the Eertree
}
/**
* Add will only add at most 1 node to the tree.
* We get the max suffix palindrome with the same character before it
* so we can get cQc which will be the new palindrome, c otherwise
* If the node is already in the tree then we return 0 and create no new nodes
* @param {Character} c
* @returns int 1 if it created a new node an 0 otherwise
*/
add(c){
/**
* Traverse the suffix palindromes of T in the order of decreasing length
* Keep traversing until we get to imaginary node or until T[len - k] = a
* @param {Node} startNode
* @param {Character} a
* @returns {Node} u
*/
const getMaxSuffixPalindrome = (startNode, a) =>{
let u = startNode;
let n = this.s.length;
let k = u.length;
while(u !== this.imaginary && this.s[n - k - 1] !== a){
if(u === u.link){
throw new Error('Infinite Loop');
}
u = u.link;
k = u.length;
}
return u;
};
let Q = getMaxSuffixPalindrome(this.maxSuffixOfT, c);
let createNewNode = !(Q.edges.has(c));
if(createNewNode){
let P = new Node();
P.length = Q.length + 2;
// this is because Q is a palindrome and the suffix and prefix == c so cQc = P
//P.length == 1 if Q is the imaginary node
if(P.length === 1){
P.link = this.empty;
P.palindrome = c;
}
else{
/**
* Now we need to find the node to suffix link to
* Continue traversing suffix palindromes of T starting with the suffix
* we found earlier 's link
*/
P.link = getMaxSuffixPalindrome(Q.link, c).edges.get(c);
P.palindrome = c + Q.palindrome + c;
}
P.parent = Q;
Q.edges.set(c, P);
}
this.maxSuffixOfT = Q.edges.get(c);
this.s += c;
return createNewNode === true ? 1 : 0;
}
traverse(){
let subpalindromes = [];
const dfs = (node) => {
if(node !== this.imaginary && node !== this.empty){
subpalindromes.push(node.palindrome);
}
for(let [_, childNode] of node.edges){
dfs(childNode);
}
}
dfs(this.imaginary);
dfs(this.empty);
return subpalindromes;
}
}
var getSubpalindromes = function(s) {
let eertree = new Eertree();
for(let c of s){
eertree.add(c);
}
return eertree.traverse();
}
console.log(getSubpalindromes('eertree'));

View file

@ -0,0 +1,105 @@
use std::collections::HashMap;
use std::convert::TryInto;
struct Node {
length: isize,
edges: HashMap<u8, usize>,
suffix: usize,
}
impl Node {
fn new(length: isize, suffix: usize) -> Self {
Node {
length,
suffix,
edges: HashMap::new(),
}
}
}
const EVEN_ROOT: usize = 0;
const ODD_ROOT: usize = 1;
fn eertree(s: &[u8]) -> Vec<Node> {
let mut tree = vec![
Node::new(0, ODD_ROOT), // even root
Node::new(-1, ODD_ROOT), // odd root
];
let mut suffix = ODD_ROOT;
for (i, &c) in s.iter().enumerate() {
let mut n = suffix;
let mut k;
loop {
k = tree[n].length;
let k_plus_one: usize = (k + 1).try_into().unwrap_or(0);
if let Some(b) = i.checked_sub(k_plus_one) {
if b < s.len() && s[b] == c {
break;
}
}
n = tree[n].suffix;
}
if tree[n].edges.contains_key(&c) {
suffix = tree[n].edges[&c];
continue;
}
suffix = tree.len();
tree.push(Node::new(k + 2, 0));
tree[n].edges.insert(c, suffix);
if tree[suffix].length == 1 {
tree[suffix].suffix = EVEN_ROOT;
continue;
}
loop {
n = tree[n].suffix;
let tree_n_length_plus_one: usize = (tree[n].length + 1).try_into().unwrap_or(0);
if let Some(b) = i.checked_sub(tree_n_length_plus_one) {
if b < s.len() && s[b] == c {
break;
}
}
}
tree[suffix].suffix = tree[n].edges[&c];
}
tree
}
fn sub_palindromes(tree: &[Node]) -> Vec<String> {
let mut result = Vec::new();
fn children(node: usize, p: String, tree: &[Node], result: &mut Vec<String>) {
for (&c, &n) in &tree[node].edges {
let c = c as char;
let p_new = format!("{}{}{}", c, p, c);
result.push(p_new.clone());
children(n, p_new, tree, result);
}
}
children(EVEN_ROOT, String::new(), tree, &mut result);
for (&c, &n) in &tree[ODD_ROOT].edges {
let c = c as char;
let p = c.to_string();
result.push(p.clone());
children(n, p, tree, &mut result);
}
result
}
fn main() {
let tree = eertree(b"eertree");
let palindromes = sub_palindromes(&tree);
for palindrome in palindromes {
println!("{}", palindrome);
}
}