diff --git a/package.json b/package.json index 91e3ff2..2887fb8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "data-structure-typed", - "version": "1.36.3", + "version": "1.36.4", "description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.", "main": "dist/index.js", "module": "lib/index.js", diff --git a/src/data-structures/trie/trie.ts b/src/data-structures/trie/trie.ts index fc1d6f4..608aea5 100644 --- a/src/data-structures/trie/trie.ts +++ b/src/data-structures/trie/trie.ts @@ -7,19 +7,19 @@ */ export class TrieNode { constructor(v: string) { - this._val = v; + this._key = v; this._isEnd = false; this._children = new Map(); } - private _val; + private _key; - get val(): string { - return this._val; + get key(): string { + return this._key; } - set val(v: string) { - this._val = v; + set key(v: string) { + this._key = v; } protected _children: Map; @@ -44,8 +44,9 @@ export class TrieNode { } export class Trie { - constructor(words?: string[]) { + constructor(words?: string[], caseSensitive = true) { this._root = new TrieNode(''); + this._caseSensitive = caseSensitive; if (words) { for (const i of words) { this.add(i); @@ -62,9 +63,11 @@ export class Trie { set root(v: TrieNode) { this._root = v; } + private _caseSensitive: boolean; add(word: string): boolean { - let cur = this._root; + word = this._caseProcess(word); + let cur = this.root; for (const c of word) { let nodeC = cur.children.get(c); if (!nodeC) { @@ -78,7 +81,8 @@ export class Trie { } has(input: string): boolean { - let cur = this._root; + input = this._caseProcess(input); + let cur = this.root; for (const c of input) { const nodeC = cur.children.get(c); if (!nodeC) return false; @@ -86,8 +90,14 @@ export class Trie { } return cur.isEnd; } - + private _caseProcess(input: string) { + if (!this._caseSensitive) { + input = input.toLowerCase(); // Convert input to lowercase if case insensitive + } + return input; + } remove(word: string) { + word = this._caseProcess(word); let isDeleted = false; const dfs = (cur: TrieNode, i: number): boolean => { const char = word[i]; @@ -119,6 +129,25 @@ export class Trie { return isDeleted; } + getHeight() { + const beginRoot = this.root; + let maxDepth = 1; + if (beginRoot) { + const bfs = (node: TrieNode, level: number) => { + if (level > maxDepth) { + maxDepth = level; + } + const {children} = node; + if (children) { + for (const child of children.entries()) { + bfs(child[1], level + 1); + } + } + }; + bfs(beginRoot, 1); + } + return maxDepth; + } // --- start additional methods --- /** * The function checks if a given input string has an absolute prefix in a tree data structure.Only can present as a prefix, not a word @@ -126,7 +155,8 @@ export class Trie { * @returns a boolean value. */ isAbsPrefix(input: string): boolean { - let cur = this._root; + input = this._caseProcess(input); + let cur = this.root; for (const c of input) { const nodeC = cur.children.get(c); if (!nodeC) return false; @@ -141,7 +171,8 @@ export class Trie { * @returns a boolean value. */ isPrefix(input: string): boolean { - let cur = this._root; + input = this._caseProcess(input); + let cur = this.root; for (const c of input) { const nodeC = cur.children.get(c); if (!nodeC) return false; @@ -157,15 +188,16 @@ export class Trie { * @returns a boolean value indicating whether the input string is a common prefix in the Trie data structure. */ isCommonPrefix(input: string): boolean { + input = this._caseProcess(input); let commonPre = ''; const dfs = (cur: TrieNode) => { - commonPre += cur.val; + commonPre += cur.key; if (commonPre === input) return; if (cur.isEnd) return; if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]); else return; }; - dfs(this._root); + dfs(this.root); return commonPre === input; } @@ -178,24 +210,26 @@ export class Trie { getLongestCommonPrefix(): string { let commonPre = ''; const dfs = (cur: TrieNode) => { - commonPre += cur.val; + commonPre += cur.key; if (cur.isEnd) return; if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]); else return; }; - dfs(this._root); + dfs(this.root); return commonPre; } /** * The `getAll` function returns an array of all words in a Trie data structure that start with a given prefix. - * @param [prefix] - The `prefix` parameter is a string that represents the prefix that we want to search for in the + * @param {string} prefix - The `prefix` parameter is a string that represents the prefix that we want to search for in the * trie. It is an optional parameter, so if no prefix is provided, it will default to an empty string. + * @param {number} max - The max count of words will be found * @returns an array of strings. */ - getAll(prefix = ''): string[] { + getWords(prefix = '', max = Number.MAX_SAFE_INTEGER): string[] { + prefix = this._caseProcess(prefix); const words: string[] = []; - + let found = 0; function dfs(node: TrieNode, word: string) { for (const char of node.children.keys()) { const charNode = node.children.get(char); @@ -204,11 +238,13 @@ export class Trie { } } if (node.isEnd) { + if (found > max - 1) return; words.push(word); + found++; } } - let startNode = this._root; + let startNode = this.root; if (prefix) { for (const c of prefix) { @@ -216,8 +252,8 @@ export class Trie { if (nodeC) startNode = nodeC; } } + if (startNode !== this.root) dfs(startNode, prefix); - dfs(startNode, prefix); return words; } diff --git a/test/unit/data-structures/trie/trie.test.ts b/test/unit/data-structures/trie/trie.test.ts index 00e15e4..c9571e8 100644 --- a/test/unit/data-structures/trie/trie.test.ts +++ b/test/unit/data-structures/trie/trie.test.ts @@ -3,7 +3,7 @@ import {Trie, TrieNode} from '../../../../src'; describe('TrieNode', () => { it('should create a TrieNode with the given value', () => { const node = new TrieNode('a'); - expect(node.val).toBe('a'); + expect(node.key).toBe('a'); expect(node.isEnd).toBe(false); expect(node.children.size).toBe(0); }); @@ -27,7 +27,7 @@ describe('TrieNode', () => { describe('Trie', () => { it('should create an empty Trie', () => { const trie = new Trie(); - expect(trie.root.val).toBe(''); + expect(trie.root.key).toBe(''); expect(trie.root.children.size).toBe(0); }); @@ -77,7 +77,7 @@ describe('Trie', () => { trie.add('apple'); trie.add('app'); trie.add('application'); - const words = trie.getAll('app'); + const words = trie.getWords('app'); expect(words).toEqual(['apple', 'application', 'app']); }); @@ -92,4 +92,664 @@ describe('Trie', () => { trie.remove('app'); expect(trie.has('app')).toBe(false); }); + + it('should suggestion Trie work well', () => { + const trie = new Trie(); + const products = ['carpet', 'cart', 'car', 'camera']; + products.forEach(product => trie.add(product)); + expect(trie.getWords('car', 2)).toEqual(['carpet', 'cart']); + const prods = [ + 'Phone', + 'TV', + 'Laptop', + 'Washing Machine', + 'Refrigerator', + 'Air Conditioner', + 'Mouse', + 'Keyboard', + 'Headphones', + 'Watch', + 'Fan', + 'Chair', + 'Table', + 'Bookshelf', + 'Lamp', + 'Camera', + 'Gaming Console', + 'Projector', + 'Printer', + 'Robot Vacuum', + 'Microwave', + 'Toaster', + 'Coffee Maker', + 'Blender', + 'Vacuum Cleaner', + 'Drill', + 'Router', + 'Monitor', + 'Tablet', + 'Speakers', + 'Smartwatch', + 'Hair Dryer', + 'Iron', + 'Microwave Oven', + 'Oven', + 'Blu-ray Player', + 'Carpet Cleaner', + 'Recliner', + 'Desk', + 'Pen', + 'Pencil', + 'Notepad', + 'Backpack', + 'Sunglasses', + 'Umbrella', + 'Jacket', + 'Shoes', + 'Bracelet', + 'Socks', + 'Hat', + 'Scarf', + 'Gloves', + 'Bicycle', + 'Scooter', + 'Skateboard', + 'Surfboard', + 'Soccer Ball', + 'Basketball', + 'Tennis Racket', + 'Golf Clubs', + 'Baseball Bat', + 'Fishing Rod', + 'Hiking Boots', + 'Tent', + 'Sleeping Bag', + 'Camp Stove', + 'Duffle Bag', + 'Guitar', + 'Piano', + 'Violin', + 'Drums', + 'Trumpet', + 'Harmonica', + 'Flute', + 'Microphone', + 'Amplifier', + 'Speaker System', + 'Couch', + 'Coffee Table', + 'Dining Table', + 'Sideboard', + 'Bed', + 'Mattress', + 'Pillow', + 'Blanket', + 'Rug', + 'Dresser', + 'Wardrobe', + 'Dining Chair', + 'Cabinet', + 'Shower Curtain', + 'Toothbrush', + 'Toothpaste', + 'Shampoo', + 'Soap', + 'Razor', + 'Towel', + 'Toilet Paper', + 'Laundry Detergent', + 'Dish Soap', + 'Broom', + 'Mop', + 'Trash Can', + 'Ironing Board', + 'Food Processor', + 'Slow Cooker', + 'Stand Mixer', + 'Cutting Board', + 'Knife Set', + 'Dining Set', + 'Silverware Set', + 'Bakeware Set', + 'Cookware Set', + 'Frying Pan', + 'Baking Sheet', + 'Mixing Bowls', + 'Can Opener', + 'Peeler', + 'Measuring Cups', + 'Utensil Set', + 'Dish Rack', + 'Storage Containers', + 'Trash Bags', + 'Aluminum Foil', + 'Plastic Wrap', + 'Ziplock Bags', + 'Cleaning Supplies', + 'Bath Towels', + 'Hand Towels', + 'Face Towels', + 'Bath Mat', + 'Shower Caddy', + 'Soap Dispenser', + 'Toothbrush Holder', + 'Shower Head', + 'Toilet Brush', + 'Plunger', + 'Hair Straightener', + 'Curling Iron', + 'Makeup Mirror', + 'Shaving Kit', + 'Cosmetic Bag', + 'Perfume', + 'Cologne', + 'Shower Gel', + 'Lotion', + 'Deodorant', + 'Sunscreen', + 'Toilet Paper Holder', + 'Laundry Basket', + 'Step Stool', + 'Flashlight', + 'Batteries', + 'Power Strip', + 'Extension Cord', + 'Toolbox', + 'Screwdriver Set', + 'Wrench', + 'Pliers', + 'Hammer', + 'Tape Measure', + 'Level', + 'Utility Knife', + 'Cordless Drill', + 'Safety Glasses', + 'Tool Belt', + 'Ladder', + 'Paint Brushes', + 'Paint Rollers', + 'Drop Cloth', + "Painter's Tape", + 'Paint Cans', + 'Wallpaper', + 'Wallpaper Paste', + 'Wallpaper Brush', + 'Wallpaper Roller', + 'Curtains', + 'Curtain Rod', + 'Curtain Rings', + 'Blinds', + 'Rugs', + 'Wall Clock', + 'Alarm Clock', + 'Desk Lamp', + 'Ceiling Fan', + 'Chandelier', + 'Floor Lamp', + 'Bedside Lamp', + 'Lawn Mower', + 'Hedge Trimmer', + 'Leaf Blower', + 'Garden Hose', + 'Sprinkler', + 'Gardening Tools', + 'Grill', + 'BBQ Tools', + 'Cooler', + 'Picnic Basket', + 'Camping Gear', + 'Pocket Knife', + 'Fishing Gear', + 'Boat', + 'Life Jacket', + 'Swimwear', + 'Beach Towel', + 'Beach Umbrella', + 'Wetsuit', + 'Snowboard', + 'Ski Equipment', + 'Snow Boots', + 'Snow Gloves', + 'Snow Goggles', + 'Snowshoes', + 'Sled', + 'Ice Skates', + 'Frisbee', + 'Pool Table', + 'Ping Pong Table', + 'Dartboard', + 'Chess Set', + 'Board Games', + 'Playing Cards', + 'Puzzle', + 'Video Games', + 'Gaming Chair', + 'VR Headset', + 'Binoculars', + 'Telescope', + 'Drone', + 'Action Camera', + 'Smartphone', + 'Desktop Computer', + 'Scanner', + 'External Hard Drive', + 'USB Flash Drive', + 'Computer Keyboard', + 'Computer Mouse', + 'Webcam', + 'Modem', + 'Ethernet Cable', + 'Wireless Headphones', + 'Bluetooth Speaker', + 'Earbuds', + 'Fitness Tracker', + 'Running Shoes', + 'Cycling Helmet', + 'Yoga Mat', + 'Dumbbells', + 'Resistance Bands', + 'Exercise Ball', + 'Jump Rope', + 'Treadmill', + 'Exercise Bike', + 'Elliptical Machine', + 'Weight Bench', + 'Gym Bag', + 'Tennis Shoes', + 'Swimsuit', + 'Goggles', + 'Snorkel', + 'Life Vest', + 'Bicycle Helmet', + 'Roller Skates', + 'Inline Skates', + 'Luggage Set', + 'Travel Pillow', + 'Suitcase', + 'Carry-On Bag', + 'Checked Bag', + 'Tote Bag', + 'Travel Adapter', + 'Neck Pillow', + 'Sleep Mask', + 'Portable Charger', + 'Camera Bag', + 'Laptop Bag', + 'Briefcase', + 'Hiking Backpack', + 'Hydration Pack', + 'Duffel Bag', + 'Messenger Bag', + 'Shoulder Bag', + 'Clutch', + 'Wallet', + 'Crossbody Bag', + 'Satchel', + 'Bucket Bag', + 'Hobo Bag', + 'Tennis Bag', + 'Golf Bag', + 'Weekender Bag', + 'Beach Bag', + 'Ski Bag', + 'Snowboard Bag', + 'Snowshoe Bag', + 'Surfboard Bag', + 'Wakeboard Bag', + 'Kiteboard Bag', + 'Skateboard Bag', + 'Roller Skates Bag', + 'Scuba Gear Bag', + 'Fishing Rod Bag', + 'Guitar Case', + 'Violin Case', + 'Trumpet Case', + 'Flute Case', + 'Clarinet Case', + 'Saxophone Case', + 'Keyboard Case', + 'Drum Case', + 'Speaker Case', + 'Microphone Case', + 'Camera Case', + 'Tripod Bag', + 'Binocular Case', + 'Telescope Case', + 'Art Supplies', + 'Paints', + 'Brushes', + 'Canvas', + 'Easel', + 'Sketchbook', + 'Pencils', + 'Watercolors', + 'Oil Paints', + 'Acrylic Paints', + 'Charcoal', + 'Pastels', + 'Markers', + 'Colored Pencils', + 'Crayons', + 'Chalk', + 'Ink', + 'Pottery Wheel', + 'Clay', + 'Pottery Tools', + 'Knitting Needles', + 'Yarn', + 'Crochet Hooks', + 'Sewing Machine', + 'Fabric', + 'Thread', + 'Sewing Needles', + 'Embroidery Hoop', + 'Cross-Stitch Kit', + 'Quilting Kit', + 'Model Kit', + 'Remote Control Car', + 'Train Set', + 'LEGO Set', + 'Building Blocks', + 'Dollhouse', + 'Action Figures', + 'Video Game Console', + 'Controller', + 'Virtual Reality Headset', + 'Poker Set', + 'Checkers Set', + 'Backgammon Set', + 'Dominoes Set', + 'Jigsaw Puzzle', + 'Racing Game', + 'Adventure Game', + 'Role-Playing Game', + 'First-Person Shooter', + 'Simulation Game', + 'Strategy Game', + 'Sports Game', + 'RPG Game', + 'Action-Adventure Game', + 'Fighting Game', + 'Platform Game', + 'Music Game', + 'Educational Game', + 'Puzzle Game', + 'Arcade Game', + 'Card Game', + 'Board Game', + 'Outdoor Game', + 'Indoor Game', + 'Word Game', + 'Brain Teaser', + 'Logic Puzzle', + 'Trivia Game', + 'Classic Game', + 'Party Game', + 'Family Game', + "Children's Game", + 'Adult Game', + 'Dice Game', + 'Tile Game', + 'Electronic Game', + 'Video Game', + 'Retro Game', + 'Computer Game', + 'Console Game', + 'Mobile Game', + 'PC Game', + 'VR Game', + 'Deck-Building Game', + 'Cooperative Game', + 'Competitive Game', + 'Social Deduction Game', + 'Trading Card Game', + 'Collectible Card Game', + 'Miniatures Game', + 'Tabletop Game', + 'War Game', + 'Fantasy Game', + 'Science Fiction Game', + 'Horror Game', + 'Mystery Game', + 'Abstract Game', + 'Eurogame', + 'Ameritrash Game', + 'Wargame', + '2-Player Game', + 'Drinking Game', + 'Action Figure', + 'Playset', + 'Educational Toy', + 'Stuffed Animal', + 'Doll', + 'Remote Control Toy', + 'Toy Car', + 'Toy Train', + 'Pretend Play Toy', + 'Construction Toy', + 'Art and Craft Kit', + 'Musical Toy', + 'Science Toy', + 'STEM Toy', + 'Puzzle Toy', + 'Building Toy', + 'Magnetic Toy', + 'Robot Toy', + 'Outdoor Toy', + 'Sports Toy', + 'Board Game Expansion', + 'Shooter Game', + 'Learning Toy', + 'Teaching Aid', + 'Flashcards', + 'Alphabet Blocks', + 'Educational Books', + 'Math Toy', + 'Science Kit', + 'Geography Toy', + 'History Toy', + 'Language Learning Toy', + 'Music Toy', + 'Art Toy', + 'STEM Kit', + 'Coding Toy', + 'Robotics Kit', + 'Building Kit', + 'Logic Toy', + 'Spelling Game', + 'Memory Game', + 'Problem-Solving Toy', + 'Critical Thinking Toy', + 'Math Game', + 'Science Game', + 'Geography Game', + 'History Game', + 'Language Learning Game', + 'Art Game', + 'Coding Game', + 'Robotics Game', + 'Building Game', + 'Memory Card', + 'Flash Drive', + 'Internal Hard Drive', + 'Solid State Drive', + 'Optical Drive', + 'USB Hub', + 'Computer Monitor', + 'Mouse Pad', + 'Laptop Stand', + 'Ink Cartridges', + 'Printer Paper', + 'Wireless Router', + 'Wi-Fi Extender', + 'Network Switch', + 'Headset', + 'External Sound Card', + 'Surge Protector', + 'Uninterruptible Power Supply', + 'Cable Management', + 'Office Chair', + 'File Cabinet', + 'Shelves', + 'Filing Supplies', + 'Stapler', + 'Staples', + 'Paper Clips', + 'Binder Clips', + 'Rubber Bands', + 'Envelopes', + 'Mailing Labels', + 'Address Labels', + 'Tape Dispenser', + 'Scissors', + 'Tape', + 'Glue', + 'Whiteboard', + 'Dry Erase Markers', + 'Corkboard', + 'Bulletin Board', + 'Push Pins', + 'Thumbtacks', + 'Desktop Organizer', + 'Calendar', + 'Planner', + 'Notebooks', + 'Legal Pads', + 'Notepads', + 'Ballpoint Pens', + 'Rollerball Pens', + 'Gel Pens', + 'Fountain Pens', + 'Highlighters', + 'Erasers', + 'Pencil Sharpeners', + 'Watercolor Paints', + 'Paintbrushes', + 'Easels', + 'Sketchbooks', + 'Drawing Paper', + 'Scrapbooking Supplies', + 'Craft Paper', + 'Craft Tools', + 'Origami Paper', + 'Calligraphy Supplies', + 'Printmaking Supplies', + 'Molding Clay', + 'Glazes', + 'Kiln', + 'Palette', + 'Canvas Boards', + 'Canvas Rolls', + 'Canvas Panels', + 'Stretched Canvas', + 'Oil Pastels', + 'Watercolor Pencils', + 'Pastel Paper', + 'Fixative Spray', + 'Eraser', + 'Pencil Sharpener', + 'Drawing Pens', + 'Calligraphy Set', + 'Ink Pens', + 'Sketching Charcoal', + 'Blending Stumps', + 'Watercolor Paper', + 'Watercolor Brushes', + 'Watercolor Palette', + 'Watercolor Mediums', + 'Watercolor Ground', + 'Watercolor Markers', + 'Acrylic Brushes', + 'Acrylic Mediums', + 'Palette Knives', + 'Gesso', + 'Acrylic Paper', + 'Airbrush Supplies', + 'Oil Brushes', + 'Oil Mediums', + 'Linseed Oil', + 'Turpentine', + 'Odorless Mineral Spirits', + 'Paper', + 'Drawing Ink', + 'Modeling Tools', + 'Pottery Brushes', + 'Throwing Bats', + 'Apron', + 'Wheel Throwing Kit', + 'Kiln Accessories', + 'Pottery Stamps', + 'Pottery Books', + 'Sculpting Tools', + 'Carving Tools', + 'Wood Carving Tools', + 'Stone Carving Tools', + 'Clay Sculpting Tools', + 'Pottery Tool Set', + 'Pottery Tool Kit', + 'Clay Extruder', + 'Pottery Rib Tools', + 'Sponge', + 'Kiln Furniture', + 'Pyrometer', + 'Kiln Shelves', + 'Kiln Posts', + 'Kiln Stilts', + 'Pottery Wire', + 'Ceramic Tiles', + 'Ceramic Glaze', + 'Raku Glaze', + 'Porcelain Glaze', + 'High-Fire Glaze', + 'Low-Fire Glaze', + 'Cone 6 Glaze', + 'Cone 10 Glaze', + 'Underglaze', + 'Slip', + 'Pottery Clay', + 'Clay Sculpture', + 'Pottery Figurines', + 'Pottery Mugs', + 'Pottery Bowls', + 'Pottery Plates', + 'Pottery Vases', + 'Pottery Teapots', + 'Pottery Platters', + 'Pottery Pitchers', + 'Pottery Planters', + 'Pottery Sculptures', + 'Pottery Wall Art', + 'Pottery Tiles', + 'Pottery Dinnerware', + 'Pottery Serveware', + 'Pottery Bakeware', + 'Pottery Home Decor', + 'Pottery Jewelry', + 'Pottery Kiln', + 'Ceramic Sculpture', + 'Ceramic Figurines', + 'Ceramic Mugs', + 'Ceramic Bowls', + 'Ceramic Plates', + 'Ceramic Vases', + 'Ceramic Teapots', + 'Ceramic Platters', + 'Ceramic Pitchers', + 'Ceramic Planters', + 'Ceramic Sculptures', + 'Ceramic Wall Art', + 'Ceramic Dinnerware', + 'Ceramic Serveware', + 'Ceramic Bakeware', + 'Ceramic Home Decor', + 'Ceramic Jewelry', + 'Ceramic Kiln', + 'Ceramic Wheel', + 'Pottery Glazes', + 'Pottery Wheels', + 'Modeling Clay' + ]; + prods.forEach(product => trie.add(product)); + expect(trie.getWords('air')).toEqual([]); + }); });