diff --git a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go b/ciphers/diffiehellman/diffiehellmankeyexchange.go similarity index 89% rename from ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go rename to ciphers/diffiehellman/diffiehellmankeyexchange.go index 8d82b100f..ae26b1f09 100644 --- a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange.go +++ b/ciphers/diffiehellman/diffiehellmankeyexchange.go @@ -1,6 +1,6 @@ -// Package diffie_hellman_key_exchange implements Deffie Hellman Key Exchange Algorithm +// Package diffiehellman implements Deffie Hellman Key Exchange Algorithm // for more information watch : https://www.youtube.com/watch?v=NmM9HA2MQGI -package diffie_hellman_key_exchange +package diffiehellman const ( generator = 3 diff --git a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go b/ciphers/diffiehellman/diffiehellmankeyexchange_test.go similarity index 97% rename from ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go rename to ciphers/diffiehellman/diffiehellmankeyexchange_test.go index 6865f6c63..7fe5ca7b9 100644 --- a/ciphers/diffie_hellman_key_exchange/diffiehellmankeyexchange_test.go +++ b/ciphers/diffiehellman/diffiehellmankeyexchange_test.go @@ -1,4 +1,4 @@ -package diffie_hellman_key_exchange +package diffiehellman import ( "crypto/rand" diff --git a/ciphers/xor/xor.go b/ciphers/xor/xor.go index 26a3c0225..0296c97ce 100644 --- a/ciphers/xor/xor.go +++ b/ciphers/xor/xor.go @@ -1,6 +1,6 @@ -// Package xor_cipher is an encryption algorithm that operates the exclusive disjunction(XOR) +// Package xor is an encryption algorithm that operates the exclusive disjunction(XOR) // ref: https://en.wikipedia.org/wiki/XOR_cipher -package xor_cipher +package xor // Encrypt encrypts with Xor encryption after converting each character to byte // The returned value might not be readable because there is no guarantee diff --git a/ciphers/xor/xor_test.go b/ciphers/xor/xor_test.go index 48b266390..999755188 100644 --- a/ciphers/xor/xor_test.go +++ b/ciphers/xor/xor_test.go @@ -1,4 +1,4 @@ -package xor_cipher +package xor import ( "fmt" diff --git a/conversions/roman_to_integer/romantointeger.go b/conversions/romantointeger.go similarity index 100% rename from conversions/roman_to_integer/romantointeger.go rename to conversions/romantointeger.go diff --git a/conversions/roman_to_integer/romantointeger_test.go b/conversions/romantointeger_test.go similarity index 100% rename from conversions/roman_to_integer/romantointeger_test.go rename to conversions/romantointeger_test.go diff --git a/data_structures/binary_tree/binarysearchtree.go b/data_structures/binary_tree/binarysearchtree.go deleted file mode 100644 index dde09d99d..000000000 --- a/data_structures/binary_tree/binarysearchtree.go +++ /dev/null @@ -1,37 +0,0 @@ -// Binary search tree -// https://en.wikipedia.org/wiki/Binary_search_tree - -package binarytree - -// import ( -// "fmt" -// ) - -// func main() { -//t := &BTree{nil} -//InOrder(t.Root) -//t.Root = Insert(t.Root, 30) -//t.Root = Insert(t.Root, 20) -//t.Root = Insert(t.Root, 15) -//t.Root = Insert(t.Root, 10) -//t.Root = Insert(t.Root, 12) -//t.Root = Insert(t.Root, 9) -//t.Root = Insert(t.Root, 11) -//t.Root = Insert(t.Root, 17) -//fmt.Print(t.Depth(), "\n") -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 10) -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 30) -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 15) -//InOrder(t.Root) -//fmt.Print("\n") -//t.Root = BstDelete(t.Root, 20) -//InOrder(t.Root) -//fmt.Print("\n") -//fmt.Print(t.Depth(), "\n") -// } diff --git a/data_structures/binary_tree/binarytree.go b/data_structures/binary_tree/binarytree.go deleted file mode 100644 index 4eeca8da9..000000000 --- a/data_structures/binary_tree/binarytree.go +++ /dev/null @@ -1,38 +0,0 @@ -// Package binarytree basic binary tree and related operations -package binarytree - -/* -func main() { - t := BTree{nil} - t.Root = NewNode(0) - t.Root.left = NewNode(1) - t.Root.right = NewNode(2) - t.Root.left.left = NewNode(3) - t.Root.left.right = NewNode(4) - t.Root.right.left = NewNode(5) - t.Root.right.right = NewNode(6) - t.Root.right.right.right = NewNode(10) - - InOrder(t.Root) - fmt.Print("\n") - PreOrder(t.Root) - fmt.Print("\n") - PostOrder(t.Root) - fmt.Print("\n") - LevelOrder(t.Root) - fmt.Print("\n") - fmt.Print(t.Depth(), "\n") - var list = AccessNodesByLayer(t.Root) - fmt.Println("{") - for i, v := range list { - for _, v2 := range v { - fmt.Print(" [", v2, "]") - } - if i != len(list)-1 { - fmt.Print(",") - } - fmt.Println() - } - fmt.Println("}") -} -*/ diff --git a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go b/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go deleted file mode 100644 index 7df7abcef..000000000 --- a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist.go +++ /dev/null @@ -1,168 +0,0 @@ -// Package doubly_linkedlist demonstration of doubly linked list in golang -package doubly_linkedlist - -import "fmt" - -// Node structure for a Node in the linkedlist -type Node struct { - val int - next *Node - prev *Node -} - -// DoubleLinkedList structure with just the head Node -type DoubleLinkedList struct { - head *Node -} - -// NewNode to avoid mistakes when using pointer vs struct for new Node creation -func NewNode(val int) *Node { - n := &Node{} - n.val = val - n.next = nil - n.prev = nil - return n -} - -// AddAtBeg Add a node to the beginning of the linkedlist -func (ll *DoubleLinkedList) AddAtBeg(val int) { - n := NewNode(val) - n.next = ll.head - - if ll.head != nil { - ll.head.prev = n - } - - ll.head = n - -} - -// AddAtEnd Add a node at the end of the linkedlist -func (ll *DoubleLinkedList) AddAtEnd(val int) { - n := NewNode(val) - - if ll.head == nil { - ll.head = n - return - } - - cur := ll.head - for ; cur.next != nil; cur = cur.next { - } - cur.next = n - n.prev = cur -} - -// DelAtBeg Delete the node at the beginning of the linkedlist -func (ll *DoubleLinkedList) DelAtBeg() int { - if ll.head == nil { - return -1 - } - - cur := ll.head - ll.head = cur.next - - if ll.head != nil { - ll.head.prev = nil - } - return cur.val -} - -// DetAtEnd Delete a node at the end of the linkedlist -func (ll *DoubleLinkedList) DelAtEnd() int { - // no item - if ll.head == nil { - return -1 - } - - // only one item - if ll.head.next == nil { - return ll.DelAtBeg() - } - - // more than one, go to second last - cur := ll.head - for ; cur.next.next != nil; cur = cur.next { - } - - retval := cur.next.val - cur.next = nil - return retval -} - -// Count Number of nodes in the linkedlist -func (ll *DoubleLinkedList) Count() int { - var ctr int = 0 - - for cur := ll.head; cur != nil; cur = cur.next { - ctr += 1 - } - - return ctr -} - -// Reverse Reverse the order of the linkedlist -func (ll *DoubleLinkedList) Reverse() { - var prev, next *Node - cur := ll.head - - for cur != nil { - next = cur.next - cur.next = prev - cur.prev = next - prev = cur - cur = next - } - - ll.head = prev -} - -// Display diplay the linked list -func (ll *DoubleLinkedList) Display() { - for cur := ll.head; cur != nil; cur = cur.next { - fmt.Print(cur.val, " ") - } - - fmt.Print("\n") -} - -// DisplayReverse Display the linkedlist in reverse order -func (ll *DoubleLinkedList) DisplayReverse() { - if ll.head == nil { - return - } - var cur *Node - for cur = ll.head; cur.next != nil; cur = cur.next { - } - - for ; cur != nil; cur = cur.prev { - fmt.Print(cur.val, " ") - } - - fmt.Print("\n") -} - -/* -func main() { - ll := DoubleLinkedList{} - - ll.addAtBeg(10) - ll.addAtEnd(20) - ll.display() - ll.addAtBeg(30) - ll.display() - - ll.reverse() - ll.display() - ll.displayReverse() - - fmt.Print(ll.delAtBeg(), "\n") - fmt.Print(ll.delAtEnd(), "\n") - fmt.Print("Display") - ll.display() - fmt.Print(ll.delAtBeg(), "\n") - ll.display() - fmt.Print(ll.delAtBeg(), "\n") - ll.display() -} -*/ diff --git a/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go b/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go deleted file mode 100644 index fb14fa7b8..000000000 --- a/data_structures/linkedlist/singly_linkedlist/singly_linkedlist2.go +++ /dev/null @@ -1,104 +0,0 @@ -package singly_linkedlist - -// TODO not needed because there is already an implementation of SingleLinkedList - -// import "fmt" - -// /* v is the value of node; next is the pointer to next node */ -// type node struct { -// v int -// next *node -// } - -// /* first node, called head. It points from first node to last node */ -// var head *node = nil - -// func (l *node) pushFront(val int) *node { -// /* if there's no nodes, head points to l (first node) */ -// if head == nil { -// l.v = val -// l.next = nil -// head = l -// return l -// } else { -// /* create a new node equals to head */ -// nnode := new(node) -// nnode = head -// /* create a second node with new value and `next -> nnode` -// * is this way, nnode2 is before nnode -// */ -// nnode2 := &node{ -// v: val, -// next: nnode, -// } -// /* now head is equals nnode2 */ -// head = nnode2 -// return head -// } -// } - -// func (l *node) pushBack(val int) *node { -// /* if there's no nodes, head points to l (first node) */ -// if head == nil { -// l.v = val -// l.next = nil -// head = l -// return l -// } else { -// /* read all list to last node */ -// for l.next != nil { -// l = l.next -// } -// /* allocate a new portion of memory */ -// l.next = new(node) -// l.next.v = val -// l.next.next = nil -// return l -// } -// } - -// func (l *node) popFront() *node { -// if head == nil { -// return head -// } -// /* create a new node equals to first node pointed by head */ -// cpnode := new(node) -// cpnode = head.next - -// /* now head is equals cpnode (second node) */ -// head = cpnode - -// return head -// } - -// func (l *node) popBack() *node { -// if head == nil { -// return head -// } -// /* create a new node equals to head */ -// cpnode := new(node) -// cpnode = head - -// /* read list to the penultimate node */ -// for cpnode.next.next != nil { -// cpnode = cpnode.next -// } -// /* the penultimate node points to null. In this way the last node is deleted */ -// cpnode.next = nil -// return head -// } - -// func main() { -// lista := new(node) -// lista.pushBack(25).pushBack(24).pushBack(32) /* lista: 25 24 32 */ -// lista.pushBack(56) /* lista: 25 24 32 56 */ -// lista.pushFront(36) /* lista: 36 25 24 32 56 */ -// lista.popFront() /* lista: 25 24 32 56 */ -// lista.popBack() /* lista: 25 24 32 */ - -// /* read the list until head is not nil */ -// for head != nil { -// fmt.Printf("%d ", head.v) -// head = head.next /*head points to next node */ -// } -// } diff --git a/datastructures/linkedlist/cyclicallylinkedlist/Readme.md b/datastructures/linkedlist/cyclicallylinkedlist/Readme.md deleted file mode 100644 index f42b63377..000000000 --- a/datastructures/linkedlist/cyclicallylinkedlist/Readme.md +++ /dev/null @@ -1,12 +0,0 @@ -# Linked Cyclic List -*** -## What is it? -*** -Loop lists are single or doubly-linked lists that chase their own tail: -A points to B, B points to C, C points to D, and D points to A. -They are better suited for cyclic data such as train schedules. -These lists are missing the first and last items. -Therefore, it is necessary to introduce the concept of the current position. - -This picture shows similar lists: -![Alt text](./Linked_Cyclic_List.jpg?raw=true) diff --git a/dynamic_programming/binomialcoefficient.go b/dynamic/binomialcoefficient.go similarity index 96% rename from dynamic_programming/binomialcoefficient.go rename to dynamic/binomialcoefficient.go index 56682eab6..57ac880c4 100644 --- a/dynamic_programming/binomialcoefficient.go +++ b/dynamic/binomialcoefficient.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic // func main() { // myArrayOfK := [4]int{5, 6, 7, 8} diff --git a/dynamic_programming/fibonacci.go b/dynamic/fibonacci.go similarity index 92% rename from dynamic_programming/fibonacci.go rename to dynamic/fibonacci.go index 73fb49878..288b82b1c 100644 --- a/dynamic_programming/fibonacci.go +++ b/dynamic/fibonacci.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic // https://www.geeksforgeeks.org/program-for-nth-fibonacci-number/ diff --git a/dynamic_programming/fibonacci_test.go b/dynamic/fibonacci_test.go similarity index 96% rename from dynamic_programming/fibonacci_test.go rename to dynamic/fibonacci_test.go index 0d94b8edf..db8aebae6 100644 --- a/dynamic_programming/fibonacci_test.go +++ b/dynamic/fibonacci_test.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic import ( "fmt" diff --git a/dynamic_programming/knapsack.go b/dynamic/knapsack.go similarity index 96% rename from dynamic_programming/knapsack.go rename to dynamic/knapsack.go index 7ccd64b02..032b91e79 100644 --- a/dynamic_programming/knapsack.go +++ b/dynamic/knapsack.go @@ -1,4 +1,4 @@ -package dynamic_programming +package dynamic // Knapsack Problem // https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ diff --git a/dynamic_programming/longestcommonsubsequence.go b/dynamic/longestcommonsubsequence.go similarity index 97% rename from dynamic_programming/longestcommonsubsequence.go rename to dynamic/longestcommonsubsequence.go index e251b57ad..447af9f7f 100644 --- a/dynamic_programming/longestcommonsubsequence.go +++ b/dynamic/longestcommonsubsequence.go @@ -2,7 +2,7 @@ // DP - 4 // https://www.geeksforgeeks.org/longest-common-subsequence-dp-4/ -package dynamic_programming +package dynamic // LongestCommonSubsequence function func LongestCommonSubsequence(a string, b string, m int, n int) int { diff --git a/dynamic_programming/longestpalindromicsubsequence.go b/dynamic/longestpalindromicsubsequence.go similarity index 97% rename from dynamic_programming/longestpalindromicsubsequence.go rename to dynamic/longestpalindromicsubsequence.go index da783d7f7..9ec9af31f 100644 --- a/dynamic_programming/longestpalindromicsubsequence.go +++ b/dynamic/longestpalindromicsubsequence.go @@ -1,7 +1,7 @@ // longest palindromic subsequence // http://www.geeksforgeeks.org/dynamic-programming-set-12-longest-palindromic-subsequence/ -package dynamic_programming +package dynamic // LpsRec function func LpsRec(word string, i, j int) int { diff --git a/dynamic_programming/matrixmultiplication.go b/dynamic/matrixmultiplication.go similarity index 97% rename from dynamic_programming/matrixmultiplication.go rename to dynamic/matrixmultiplication.go index ff73b1762..4449c411f 100644 --- a/dynamic_programming/matrixmultiplication.go +++ b/dynamic/matrixmultiplication.go @@ -3,7 +3,7 @@ // www.geeksforgeeks.org/dynamic_programming-set-8-matrix-chain-multiplication/ // Package dynamic_programming Package for dynamically run algorithms -package dynamic_programming +package dynamic // MatrixChainRec function func MatrixChainRec(D []int, i, j int) int { diff --git a/dynamic_programming/rodcutting.go b/dynamic/rodcutting.go similarity index 97% rename from dynamic_programming/rodcutting.go rename to dynamic/rodcutting.go index 733798a39..ce721e18b 100644 --- a/dynamic_programming/rodcutting.go +++ b/dynamic/rodcutting.go @@ -2,7 +2,7 @@ // https://en.wikipedia.org/wiki/Cutting_stock_problem // http://www.geeksforgeeks.org/dynamic-programming-set-13-cutting-a-rod/ -package dynamic_programming +package dynamic // CutRodRec solve the problem recursively: initial approach func CutRodRec(price []int, length int) int { diff --git a/genetic_algorithm/geneticalgorithm.go b/genetic/genetic.go similarity index 97% rename from genetic_algorithm/geneticalgorithm.go rename to genetic/genetic.go index 0651f4318..12afb7c2d 100644 --- a/genetic_algorithm/geneticalgorithm.go +++ b/genetic/genetic.go @@ -1,8 +1,8 @@ -// package geneticalgorithm provides functions to work with strings +// Package genetic provides functions to work with strings // using genetic algorithm. https://en.wikipedia.org/wiki/Genetic_algorithm // // Author: D4rkia -package geneticalgorithm +package genetic import ( "errors" @@ -60,7 +60,7 @@ type Result struct { Best PopulationItem } -// GenerateString generates PopultaionItem based on the imputed target +// GeneticString generates PopultaionItem based on the imputed target // string, and a set of possible runes to build a string with. In order // to optimise string generation additional configurations can be provided // with Conf instance. Empty instance of Conf (&Conf{}) can be provided, diff --git a/genetic_algorithm/geneticalgorithm_test.go b/genetic/geneticalgorithm_test.go similarity index 96% rename from genetic_algorithm/geneticalgorithm_test.go rename to genetic/geneticalgorithm_test.go index a57463963..0971331fd 100644 --- a/genetic_algorithm/geneticalgorithm_test.go +++ b/genetic/geneticalgorithm_test.go @@ -1,4 +1,4 @@ -package geneticalgorithm +package genetic import ( "testing" diff --git a/graphs/breadth_first_search/breadthfirstsearch.go b/graph/breadthfirstsearch.go similarity index 53% rename from graphs/breadth_first_search/breadthfirstsearch.go rename to graph/breadthfirstsearch.go index c80bf8209..620d96a3f 100644 --- a/graphs/breadth_first_search/breadthfirstsearch.go +++ b/graph/breadthfirstsearch.go @@ -1,14 +1,13 @@ -// Package search Graph search algorithms +// Package graph demonstates Graph search algorithms // reference: https://en.wikipedia.org/wiki/Tree_traversal -package breadth_first_search +package graph -/*BreadthFirstSearch is an algorithm for traversing and searching graph data structures. - It starts at an arbitrary node of a graph, and explores all of the neighbor nodes - at the present depth prior to moving on to the nodes at the next depth level. - Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) - Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) -reference: https://en.wikipedia.org/wiki/Breadth-first_search -*/ +// BreadthFirstSearch is an algorithm for traversing and searching graph data structures. +// It starts at an arbitrary node of a graph, and explores all of the neighbor nodes +// at the present depth prior to moving on to the nodes at the next depth level. +// Worst-case performance O(|V|+|E|)=O(b^{d})}O(|V|+|E|)=O(b^{d}) +// Worst-case space complexity O(|V|)=O(b^{d})}O(|V|)=O(b^{d}) +// reference: https://en.wikipedia.org/wiki/Breadth-first_search func BreadthFirstSearch(start, end, nodes int, edges [][]int) (isConnected bool, distance int) { queue := make([]int, 0) discovered := make([]int, nodes) diff --git a/graphs/breadth_first_search/breadthfirstsearch_test.go b/graph/breadthfirstsearch_test.go similarity index 98% rename from graphs/breadth_first_search/breadthfirstsearch_test.go rename to graph/breadthfirstsearch_test.go index d80d767f5..a01db4fc1 100644 --- a/graphs/breadth_first_search/breadthfirstsearch_test.go +++ b/graph/breadthfirstsearch_test.go @@ -1,4 +1,4 @@ -package breadth_first_search +package graph import ( "testing" diff --git a/graphs/depth_first_search/depthfirstsearch.go b/graph/depthfirstsearch.go similarity index 93% rename from graphs/depth_first_search/depthfirstsearch.go rename to graph/depthfirstsearch.go index 07648e17c..a4afb7647 100644 --- a/graphs/depth_first_search/depthfirstsearch.go +++ b/graph/depthfirstsearch.go @@ -1,4 +1,4 @@ -package depth_first_search +package graph func GetIdx(target int, nodes []int) int { for i := 0; i < len(nodes); i++ { @@ -18,7 +18,7 @@ func NotExist(target int, slice []int) bool { return true } -func Dfs(start, end int, nodes []int, edges [][]bool) ([]int, bool) { +func DepthFirstSearch(start, end int, nodes []int, edges [][]bool) ([]int, bool) { var route []int var stack []int startIdx := GetIdx(start, nodes) diff --git a/graphs/floyd_warshall/floydwarshall.go b/graph/floydwarshall.go similarity index 98% rename from graphs/floyd_warshall/floydwarshall.go rename to graph/floydwarshall.go index 0a9f7e7a4..a04b60ef8 100644 --- a/graphs/floyd_warshall/floydwarshall.go +++ b/graph/floydwarshall.go @@ -1,7 +1,7 @@ // Floyd-Warshall algorithm // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm -package floyd_warshall +package graph // Matrix Defining matrix to use 2d array easier type Matrix [][]float64 diff --git a/math/sieve/sieve.go b/math/prime/sieve.go similarity index 80% rename from math/sieve/sieve.go rename to math/prime/sieve.go index 506c64216..e6b216a68 100644 --- a/math/sieve/sieve.go +++ b/math/prime/sieve.go @@ -3,10 +3,10 @@ // author(s) [Taj](https://github.com/tjgurwara99) // see sieve_test.go -package sieve +package prime // Generate generates the sequence of integers starting at 2 and sends it to the channel `ch` -func Generate(ch chan<- int) { +func GenerateChannel(ch chan<- int) { for i := 2; ; i++ { ch <- i } @@ -22,12 +22,12 @@ func Sieve(in <-chan int, out chan<- int, prime int) { } } -// GeneratePrimes returns a int slice of prime numbers up to the limit -func GeneratePrimes(limit int) []int { +// Generate returns a int slice of prime numbers up to the limit +func Generate(limit int) []int { var primes []int ch := make(chan int) - go Generate(ch) + go GenerateChannel(ch) for i := 0; i < limit; i++ { primes = append(primes, <-ch) diff --git a/math/sieve/sieve_test.go b/math/prime/sieve_test.go similarity index 93% rename from math/sieve/sieve_test.go rename to math/prime/sieve_test.go index e96f442b6..82cc63017 100644 --- a/math/sieve/sieve_test.go +++ b/math/prime/sieve_test.go @@ -3,7 +3,7 @@ // author(s) [Taj](https://github.com/tjgurwara99) // see sieve.go -package sieve +package prime import ( "reflect" @@ -17,7 +17,7 @@ func TestSieve(t *testing.T) { var testTenPrimes [10]int ch := make(chan int) - go Generate(ch) + go GenerateChannel(ch) for i := 0; i < 10; i++ { testTenPrimes[i] = <-ch @@ -37,7 +37,7 @@ func TestGeneratePrimes(t *testing.T) { firstTenPrimes := []int{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} t.Run("Testing GeneratePrimes Function", func(t *testing.T) { - testPrimes := GeneratePrimes(10) + testPrimes := Generate(10) if !reflect.DeepEqual(firstTenPrimes, testPrimes) { t.Fatal("GeneratePrimes function failed") diff --git a/other/max_subarray_sum/maxsubarraysum.go b/other/maxsubarraysum/maxsubarraysum.go similarity index 96% rename from other/max_subarray_sum/maxsubarraysum.go rename to other/maxsubarraysum/maxsubarraysum.go index 9101c4e6e..e50453b3b 100644 --- a/other/max_subarray_sum/maxsubarraysum.go +++ b/other/maxsubarraysum/maxsubarraysum.go @@ -1,7 +1,7 @@ /* O(n) solution, for calculating maximum contiguous sum in the given array. */ -package max_subarray_sum +package maxsubarraysum // Max - already defined somewhere in this repository TODO: remove this definition and add the import path func Max(x int, y int) int { diff --git a/other/monte_carlo_pi/montecarlopi.go b/other/monte_carlo_pi/montecarlopi.go deleted file mode 100644 index 2506af346..000000000 --- a/other/monte_carlo_pi/montecarlopi.go +++ /dev/null @@ -1,50 +0,0 @@ -package montecarlopi - -// import ( -// "fmt" -// "math" -// "math/rand" -// "runtime" -// "sync" -// "time" -// ) - -// func main() { -// cpus := runtime.NumCPU() -// monteCarlo := func(iterations, cpus int) float64{ -// start := time.Now() -// flow := make(chan int, int(math.Floor(float64(cpus)/2))) -// var wg sync.WaitGroup -// var total int -// miniFunc := func(iters int, flow chan int) { -// defer wg.Done() -// var inside int -// for i := 0; i < iters; i++ { -// x := rand.Float64() -// y := rand.Float64() -// if math.Hypot(x, y) <= 1 { -// inside++ -// } -// } -// flow <- inside -// } //end of minifunc -// fuxc := func(flow chan int) { -// defer wg.Done() -// for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { -// total += <-flow -// } -// } //end of fuxc -// wg.Add(int(math.Floor(float64(cpus) / 2))) -// //spawn goroutines for half the logical processors -// // This leaves free cpus for swapping -// for i := 0; i < int(math.Floor(float64(cpus)/2)); i++ { -// go miniFunc(int(math.Ceil(float64(iterations/int(math.Floor(float64(cpus)/2))))), flow) -// } -// wg.Add(1) -// go fuxc(flow) -// wg.Wait() -// fmt.Printf("took %v \n",time.Since(start)) -// return 4 * float64(total) / float64(iterations) -// }//end of monteCarlo -// fmt.Println(monteCarlo(2<<18, cpus)) -// } diff --git a/other/monte_carlo_pi/montecarlopi_test.go b/other/monte_carlo_pi/montecarlopi_test.go deleted file mode 100644 index 899fd5c46..000000000 --- a/other/monte_carlo_pi/montecarlopi_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package montecarlopi - -// import ( -// "math" -// "testing" -// ) - -// func TestMonteCarloPi(t *testing.T) { -// delta := 0.0001 - -// pi := MonteCarloPi(100000000) - -// if math.Abs(pi-math.Pi) > delta { -// t.Errorf("Given: %.4f, expected: %.4f", pi, math.Pi) -// } -// } diff --git a/other/nested_brackets/nestedbrackets.go b/other/nested/nestedbrackets.go similarity index 98% rename from other/nested_brackets/nestedbrackets.go rename to other/nested/nestedbrackets.go index b70ab2aa2..c0afd9571 100644 --- a/other/nested_brackets/nestedbrackets.go +++ b/other/nested/nestedbrackets.go @@ -1,6 +1,6 @@ // Package nested_brackets provides functions for testing // strings propper brackets nesting. -package nested_brackets +package nested // IsBalanced returns true if provided input string is properly nested. // diff --git a/other/nested_brackets/nestedbrackets_test.go b/other/nested/nestedbrackets_test.go similarity index 98% rename from other/nested_brackets/nestedbrackets_test.go rename to other/nested/nestedbrackets_test.go index 658cc4837..52fc41cfb 100644 --- a/other/nested_brackets/nestedbrackets_test.go +++ b/other/nested/nestedbrackets_test.go @@ -1,4 +1,4 @@ -package nested_brackets +package nested import ( "testing" diff --git a/other/password/generator.go b/other/password/generator.go new file mode 100644 index 000000000..b25f2f48b --- /dev/null +++ b/other/password/generator.go @@ -0,0 +1,45 @@ +// This program generates a password from a list of possible chars +// You must provide a minimum length and a maximum length +// This length is not fixed if you generate multiple passwords for the same range + +package password_generator + +import ( + "crypto/rand" + "io" + "math/big" +) + +// Generate returns a newly generated password +func Generate(minLength int, maxLength int) string { + var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~") + + length, err := rand.Int(rand.Reader, big.NewInt(int64(maxLength-minLength))) + if err != nil { + panic(err) // handle this gracefully + } + length.Add(length, big.NewInt(int64(minLength))) + + intLength := int(length.Int64()) + + newPassword := make([]byte, intLength) + randomData := make([]byte, intLength+intLength/4) + clen := byte(len(chars)) + maxrb := byte(256 - (256 % len(chars))) + i := 0 + for { + if _, err := io.ReadFull(rand.Reader, randomData); err != nil { + panic(err) + } + for _, c := range randomData { + if c >= maxrb { + continue + } + newPassword[i] = chars[c%clen] + i++ + if i == intLength { + return string(newPassword) + } + } + } +} diff --git a/other/password_generator/passwordgenerator.go b/other/password_generator/passwordgenerator.go deleted file mode 100644 index f795c16a1..000000000 --- a/other/password_generator/passwordgenerator.go +++ /dev/null @@ -1,53 +0,0 @@ -// This program generates a password from a list of possible chars -// You must provide a minimum length and a maximum length -// This length is not fixed if you generate multiple passwords for the same range - -package password_generator - -import ( - crand "crypto/rand" - "io" - "math/rand" -) - -// GeneratePassword returns a newly generated password -func GeneratePassword(minLength int, maxLength int) string { - var chars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+,.?/:;{}[]`~") - - var length = rand.Intn(maxLength-minLength) + minLength - - newPassword := make([]byte, length) - randomData := make([]byte, length+(length/4)) - clen := byte(len(chars)) - maxrb := byte(256 - (256 % len(chars))) - i := 0 - for { - if _, err := io.ReadFull(crand.Reader, randomData); err != nil { - panic(err) - } - for _, c := range randomData { - if c >= maxrb { - continue - } - newPassword[i] = chars[c%clen] - i++ - if i == length { - return string(newPassword) - } - } - } -} - -// func main() { -// rand.Seed(time.Now().Unix()) - -// fmt.Print("Please specify a minimum length: ") -// var minLength int -// fmt.Scanf("%d", &minLength) - -// fmt.Print("Please specify a maximum length: ") -// var maxLength int -// fmt.Scanf("%d", &maxLength) - -// fmt.Printf("Your generated password is %v\n", generatePassword(minLength, maxLength)) -// } diff --git a/searches/binary_search/binarysearch.go b/search/binary.go similarity index 60% rename from searches/binary_search/binarysearch.go rename to search/binary.go index f3c9b7840..e72e3e9d2 100644 --- a/searches/binary_search/binarysearch.go +++ b/search/binary.go @@ -1,22 +1,22 @@ -package binarysearch +package search -// BinarySearch Binary Search -func BinarySearch(array []int, target int, lowIndex int, highIndex int) int { +// Binary Binary Search +func Binary(array []int, target int, lowIndex int, highIndex int) int { if highIndex < lowIndex || len(array) == 0 { return -1 } mid := (highIndex + lowIndex) / 2 if array[mid] > target { - return BinarySearch(array, target, lowIndex, mid-1) + return Binary(array, target, lowIndex, mid-1) } else if array[mid] < target { - return BinarySearch(array, target, mid+1, highIndex) + return Binary(array, target, mid+1, highIndex) } else { return mid } } -// IterBinarySearch Iter Binary Search -func IterBinarySearch(array []int, target int, lowIndex int, highIndex int) int { +// BinaryIterative Iterative Binary Search +func BinaryIterative(array []int, target int, lowIndex int, highIndex int) int { startIndex := lowIndex endIndex := highIndex var mid int diff --git a/search/binary_test.go b/search/binary_test.go new file mode 100644 index 000000000..70f4a7bcb --- /dev/null +++ b/search/binary_test.go @@ -0,0 +1,23 @@ +package search + +import ( + "testing" +) + +func TestBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := Binary(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} + +func TestIterBinarySearch(t *testing.T) { + for _, test := range searchTests { + actual := BinaryIterative(test.data, test.key, 0, len(test.data)-1) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/searches/interpolation_search.go/interpolationsearch.go b/search/interpolation.go similarity index 59% rename from searches/interpolation_search.go/interpolationsearch.go rename to search/interpolation.go index 7e4de0277..4bd277877 100644 --- a/searches/interpolation_search.go/interpolationsearch.go +++ b/search/interpolation.go @@ -1,18 +1,15 @@ -package interpolationsearch - -/* -InterpolationSearch searches for the entity in the given sortedData. -if the entity is present, it will return the index of the entity, if not -1 will be returned. -see: https://en.wikipedia.org/wiki/Interpolation_search -Complexity - Worst: O(N) - Average: O(log(log(N)) if the elements are uniformly distributed - Best: O(1) - -Example - fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) -*/ -func InterpolationSearch(sortedData []int, guess int) int { +package search + +// Interpolation searches for the entity in the given sortedData. +// if the entity is present, it will return the index of the entity, if not -1 will be returned. +// see: https://en.wikipedia.org/wiki/Interpolation_search +// Complexity +// Worst: O(N) +// Average: O(log(log(N)) if the elements are uniformly distributed +// Best: O(1) +// Example +// fmt.Println(InterpolationSearch([]int{1, 2, 9, 20, 31, 45, 63, 70, 100},100)) +func Interpolation(sortedData []int, guess int) int { if len(sortedData) == 0 { return -1 } diff --git a/search/interpolation_test.go b/search/interpolation_test.go new file mode 100644 index 000000000..848ddf0aa --- /dev/null +++ b/search/interpolation_test.go @@ -0,0 +1,12 @@ +package search + +import "testing" + +func TestInterpolation(t *testing.T) { + for _, test := range searchTests { + actual := Interpolation(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/search/linear.go b/search/linear.go new file mode 100644 index 000000000..c442630c6 --- /dev/null +++ b/search/linear.go @@ -0,0 +1,11 @@ +package search + +// Linear Simple linear search algorithm that iterates over all elements of an array in the worst case scenario +func Linear(array []int, query int) int { + for i, item := range array { + if item == query { + return i + } + } + return -1 +} diff --git a/search/linear_test.go b/search/linear_test.go new file mode 100644 index 000000000..6f02db8cf --- /dev/null +++ b/search/linear_test.go @@ -0,0 +1,14 @@ +package search + +import ( + "testing" +) + +func TestLinear(t *testing.T) { + for _, test := range searchTests { + actual := Linear(test.data, test.key) + if actual != test.expected { + t.Errorf("test %s failed", test.name) + } + } +} diff --git a/searches/linear_search/linearsearch_test.go b/search/testcases.go similarity index 64% rename from searches/linear_search/linearsearch_test.go rename to search/testcases.go index 121dcd4a6..65e9bbd06 100644 --- a/searches/linear_search/linearsearch_test.go +++ b/search/testcases.go @@ -1,8 +1,4 @@ -package linear_search - -import ( - "testing" -) +package search type searchTest struct { data []int @@ -11,6 +7,8 @@ type searchTest struct { name string } +// Note that these are immutable therefore they are shared among all the search tests. +// If your algorithm is mutating these then it is advisable to create separate test cases. var searchTests = []searchTest{ //Sanity {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, @@ -22,12 +20,3 @@ var searchTests = []searchTest{ //Empty slice {[]int{}, 2, -1, "Empty"}, } - -func TestLinearSearch(t *testing.T) { - for _, test := range searchTests { - actual := LinearSearch(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/binary_search/binarysearch_test.go b/searches/binary_search/binarysearch_test.go deleted file mode 100644 index 82909e99c..000000000 --- a/searches/binary_search/binarysearch_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package binarysearch - -import ( - "testing" -) - -type searchTest struct { - data []int - key int - expected int - name string -} - -var searchTests = []searchTest{ - //Sanity - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, - //Absent - {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, - {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, - //Empty slice - {[]int{}, 2, -1, "Empty"}, -} - -func TestBinarySearch(t *testing.T) { - for _, test := range searchTests { - actual := BinarySearch(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} - -func TestIterBinarySearch(t *testing.T) { - for _, test := range searchTests { - actual := IterBinarySearch(test.data, test.key, 0, len(test.data)-1) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/interpolation_search.go/interpolation_search_test.go b/searches/interpolation_search.go/interpolation_search_test.go deleted file mode 100644 index 0ca829f14..000000000 --- a/searches/interpolation_search.go/interpolation_search_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package interpolationsearch - -import "testing" - -type searchTest struct { - data []int - key int - expected int - name string -} - -var searchTests = []searchTest{ - //Sanity - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 1, 0, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 5, 4, "Sanity"}, - {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 10, 9, "Sanity"}, - //Absent - {[]int{1, 4, 5, 6, 7, 10}, -25, -1, "Absent"}, - {[]int{1, 4, 5, 6, 7, 10}, 25, -1, "Absent"}, - //Empty slice - {[]int{}, 2, -1, "Empty"}, -} - -func TestInterpolationSearch(t *testing.T) { - for _, test := range searchTests { - actual := InterpolationSearch(test.data, test.key) - if actual != test.expected { - t.Errorf("test %s failed", test.name) - } - } -} diff --git a/searches/linear_search/linearsearch.go b/searches/linear_search/linearsearch.go deleted file mode 100644 index 89be4fd8b..000000000 --- a/searches/linear_search/linearsearch.go +++ /dev/null @@ -1,11 +0,0 @@ -package linear_search - -// LinearSearch Simple linear search algorithm that iterates over all elements of an array in the worst case scenario -func LinearSearch(array []int, query int) int { - for i, item := range array { - if item == query { - return i - } - } - return -1 -} diff --git a/strings/ahocorasick/advancedahocorasick.go b/strings/ahocorasick/advancedahocorasick.go new file mode 100644 index 000000000..e465903a9 --- /dev/null +++ b/strings/ahocorasick/advancedahocorasick.go @@ -0,0 +1,82 @@ +package ahocorasick + +import ( + "fmt" + "time" +) + +// Advanced Function performing the Advanced Aho-Corasick alghoritm. +// Finds and prints occurrences of each pattern. +func Advanced(t string, p []string) Result { + startTime := time.Now() + occurrences := make(map[int][]int) + ac, f := BuildExtendedAc(p) + current := 0 + for pos := 0; pos < len(t); pos++ { + if GetTransition(current, t[pos], ac) != -1 { + current = GetTransition(current, t[pos], ac) + } else { + current = 0 + } + _, ok := f[current] + if ok { + for i := range f[current] { + if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 + } + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return Result{ + resultOccurrences, + } +} + +// BuildExtendedAc Functions that builds extended Aho Corasick automaton. +func BuildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { + acTrie, stateIsTerminal, f := ConstructTrie(p) + s := make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of acTrie + acToReturn = acTrie + s[i] = -1 + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := GetParent(current, acTrie) + down := s[parent] + for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { + down = s[down] + } + if StateExists(down, acToReturn) { + s[current] = GetTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] { + stateIsTerminal[current] = true + f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + } + } else { + s[current] = i //initial state? + } + } + a := ComputeAlphabet(p) // concat of all patterns in p + for j := range a { + if GetTransition(i, a[j], acToReturn) == -1 { + CreateTransition(i, a[j], i, acToReturn) + } + } + for current := 1; current < len(stateIsTerminal); current++ { + for j := range a { + if GetTransition(current, a[j], acToReturn) == -1 { + CreateTransition(current, a[j], GetTransition(s[current], a[j], acToReturn), acToReturn) + } + } + } + return acToReturn, f +} diff --git a/strings/multiple_string_matching/aho_corasick/ahocorasick_test.go b/strings/ahocorasick/advancedahocorasick_test.go similarity index 77% rename from strings/multiple_string_matching/aho_corasick/ahocorasick_test.go rename to strings/ahocorasick/advancedahocorasick_test.go index 2f3241702..996651457 100644 --- a/strings/multiple_string_matching/aho_corasick/ahocorasick_test.go +++ b/strings/ahocorasick/advancedahocorasick_test.go @@ -1,9 +1,7 @@ package ahocorasick import ( - "fmt" "reflect" - "strings" "testing" ) @@ -50,7 +48,7 @@ var testCases = []struct { }, } -func TestAhoCorasick(t *testing.T) { +func TestAdvanced(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { actual := AhoCorasick(tc.text, tc.words) @@ -63,18 +61,3 @@ func TestAhoCorasick(t *testing.T) { }) } } - -func convertToString(res Result) string { - var r strings.Builder - for key, val := range res.occurrences { - r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) - for i := range val { - r.WriteString(fmt.Sprintf("%d", val[i])) - if i != len(val)-1 { - r.WriteString(", ") - } - } - r.WriteString(". ") - } - return r.String() -} diff --git a/strings/ahocorasick/ahocorasick.go b/strings/ahocorasick/ahocorasick.go new file mode 100644 index 000000000..e052e7905 --- /dev/null +++ b/strings/ahocorasick/ahocorasick.go @@ -0,0 +1,77 @@ +package ahocorasick + +import ( + "fmt" + "time" +) + +// Result structure to hold occurrences +type Result struct { + occurrences map[string][]int +} + +// AhoCorasick Function performing the Basic Aho-Corasick algorithm. +// Finds and prints occurrences of each pattern. +func AhoCorasick(t string, p []string) Result { + startTime := time.Now() + occurrences := make(map[int][]int) + ac, f, s := BuildAc(p) + current := 0 + for pos := 0; pos < len(t); pos++ { + for GetTransition(current, t[pos], ac) == -1 && s[current] != -1 { + current = s[current] + } + if GetTransition(current, t[pos], ac) != -1 { + current = GetTransition(current, t[pos], ac) + fmt.Printf(" (Continue) \n") + } else { + current = 0 + } + _, ok := f[current] + if ok { + for i := range f[current] { + if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match + newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) + occurrences[f[current][i]] = newOccurrences + occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 + } + } + } + } + elapsed := time.Since(startTime) + fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) + var resultOccurrences = make(map[string][]int) + for key, value := range occurrences { + resultOccurrences[p[key]] = value + } + + return Result{ + resultOccurrences, + } +} + +// Functions that builds Aho Corasick automaton. +func BuildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s []int) { + acTrie, stateIsTerminal, f := ConstructTrie(p) + s = make([]int, len(stateIsTerminal)) //supply function + i := 0 //root of acTrie + acToReturn = acTrie + s[i] = -1 + for current := 1; current < len(stateIsTerminal); current++ { + o, parent := GetParent(current, acTrie) + down := s[parent] + for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { + down = s[down] + } + if StateExists(down, acToReturn) { + s[current] = GetTransition(down, o, acToReturn) + if stateIsTerminal[s[current]] { + stateIsTerminal[current] = true + f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) + } + } else { + s[current] = i //initial state? + } + } + return acToReturn, f, s +} diff --git a/strings/ahocorasick/ahocorasick_test.go b/strings/ahocorasick/ahocorasick_test.go new file mode 100644 index 000000000..366410fa1 --- /dev/null +++ b/strings/ahocorasick/ahocorasick_test.go @@ -0,0 +1,37 @@ +package ahocorasick + +import ( + "fmt" + "reflect" + "strings" + "testing" +) + +func TestAhoCorasick(t *testing.T) { + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := AhoCorasick(tc.text, tc.words) + if !reflect.DeepEqual(actual, tc.expected) { + actualString := convertToString(actual) + expectedString := convertToString(tc.expected) + t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", + tc.words, tc.text, actualString, expectedString) + } + }) + } +} + +func convertToString(res Result) string { + var r strings.Builder + for key, val := range res.occurrences { + r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) + for i := range val { + r.WriteString(fmt.Sprintf("%d", val[i])) + if i != len(val)-1 { + r.WriteString(", ") + } + } + r.WriteString(". ") + } + return r.String() +} diff --git a/strings/multiple_string_matching/patterns.txt b/strings/ahocorasick/patterns.txt similarity index 100% rename from strings/multiple_string_matching/patterns.txt rename to strings/ahocorasick/patterns.txt diff --git a/strings/ahocorasick/shared.go b/strings/ahocorasick/shared.go new file mode 100644 index 000000000..eee95c1b7 --- /dev/null +++ b/strings/ahocorasick/shared.go @@ -0,0 +1,139 @@ +package ahocorasick + +// ConstructTrie Function that constructs Trie as an automaton for a set of reversed & trimmed strings. +func ConstructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { + trie = make(map[int]map[uint8]int) + stateIsTerminal = make([]bool, 1) + f = make(map[int][]int) + state := 1 + CreateNewState(0, trie) + for i := 0; i < len(p); i++ { + current := 0 + j := 0 + for j < len(p[i]) && GetTransition(current, p[i][j], trie) != -1 { + current = GetTransition(current, p[i][j], trie) + j++ + } + for j < len(p[i]) { + stateIsTerminal = BoolArrayCapUp(stateIsTerminal) + CreateNewState(state, trie) + stateIsTerminal[state] = false + CreateTransition(current, p[i][j], state, trie) + current = state + j++ + state++ + } + if stateIsTerminal[current] { + newArray := IntArrayCapUp(f[current]) + newArray[len(newArray)-1] = i + f[current] = newArray // F(Current) <- F(Current) union {i} + } else { + stateIsTerminal[current] = true + f[current] = []int{i} // F(Current) <- {i} + } + } + return trie, stateIsTerminal, f +} + +// Contains Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. +func Contains(s []int, e int) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} + +// GetWord Function that returns word found in text 't' at position range 'begin' to 'end'. +func GetWord(begin, end int, t string) string { + for end >= len(t) { + return "" + } + d := make([]uint8, end-begin+1) + for j, i := 0, begin; i <= end; i, j = i+1, j+1 { + d[j] = t[i] + } + return string(d) +} + +// ComputeAlphabet Function that returns string of all the possible characters in given patterns. +func ComputeAlphabet(p []string) (s string) { + s = p[0] + for i := 1; i < len(p); i++ { + s = s + p[i] + } + return s +} + +// IntArrayCapUp Dynamically increases an array size of int's by 1. +func IntArrayCapUp(old []int) (new []int) { + new = make([]int, cap(old)+1) + copy(new, old) //copy(dst,src) + // old = new + return new +} + +// BoolArrayCapUp Dynamically increases an array size of bool's by 1. +func BoolArrayCapUp(old []bool) (new []bool) { + new = make([]bool, cap(old)+1) + copy(new, old) + // old = new + return new +} + +// ArrayUnion Concats two arrays of int's into one. +func ArrayUnion(to, from []int) (concat []int) { + concat = to + for i := range from { + if !Contains(concat, from[i]) { + concat = IntArrayCapUp(concat) + concat[len(concat)-1] = from[i] + } + } + return concat +} + +// GetParent Function that finds the first previous state of a state and returns it. +// Used for trie where there is only one parent. +func GetParent(state int, at map[int]map[uint8]int) (uint8, int) { + for beginState, transitions := range at { + for c, endState := range transitions { + if endState == state { + return c, beginState + } + } + } + return 0, 0 //unreachable +} + +// CreateNewState Automaton function for creating a new state 'state'. +func CreateNewState(state int, at map[int]map[uint8]int) { + at[state] = make(map[uint8]int) +} + +// CreateTransition Creates a transition for function σ(state,letter) = end. +func CreateTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { + at[fromState][overChar] = toState +} + +// GetTransition Returns ending state for transition σ(fromState,overChar), '-1' if there is none. +func GetTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { + if !StateExists(fromState, at) { + return -1 + } + toState, ok := at[fromState][overChar] + if !ok { + return -1 + } + return toState +} + +// StateExists Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. +func StateExists(state int, at map[int]map[uint8]int) bool { + _, ok := at[state] + if !ok || state == -1 || at[state] == nil { + return false + } + return true +} diff --git a/strings/multiple_string_matching/text.txt b/strings/ahocorasick/text.txt similarity index 100% rename from strings/multiple_string_matching/text.txt rename to strings/ahocorasick/text.txt diff --git a/strings/single_string_matching/bom/bom.go b/strings/bom/bom.go similarity index 100% rename from strings/single_string_matching/bom/bom.go rename to strings/bom/bom.go diff --git a/other/string_combinations/stringcombinations.go b/strings/combination/combination.go similarity index 79% rename from other/string_combinations/stringcombinations.go rename to strings/combination/combination.go index dc0f92fed..42bbdee8b 100644 --- a/other/string_combinations/stringcombinations.go +++ b/strings/combination/combination.go @@ -1,5 +1,5 @@ -// Package string_combinations ... -package string_combinations +// Package combination ... +package combination import "fmt" @@ -9,8 +9,8 @@ type Combinations struct { in []rune } -// StartCombinations ... -func StartCombinations(input string) { +// Start ... +func Start(input string) { c := &Combinations{ in: []rune(input), } diff --git a/strings/single_string_matching/horspool/horspool.go b/strings/horspool/horspool.go similarity index 100% rename from strings/single_string_matching/horspool/horspool.go rename to strings/horspool/horspool.go diff --git a/strings/single_string_matching/kmp/kmp.go b/strings/kmp/kmp.go similarity index 100% rename from strings/single_string_matching/kmp/kmp.go rename to strings/kmp/kmp.go diff --git a/strings/single_string_matching/kmp/kmp_test.go b/strings/kmp/kmp_test.go similarity index 100% rename from strings/single_string_matching/kmp/kmp_test.go rename to strings/kmp/kmp_test.go diff --git a/strings/levenshtein_distance/levenshteindistance.go b/strings/levenshtein/levenshteindistance.go similarity index 82% rename from strings/levenshtein_distance/levenshteindistance.go rename to strings/levenshtein/levenshteindistance.go index c718b1e5a..b5cdec547 100644 --- a/strings/levenshtein_distance/levenshteindistance.go +++ b/strings/levenshtein/levenshteindistance.go @@ -4,10 +4,10 @@ Parameters: two strings to compare and weights of insertion, substitution and de Output: distance between both strings */ -package levenshtein_distance +package levenshtein -// LevenshteinDistance Function that gives Levenshtein Distance -func LevenshteinDistance(str1, str2 string, icost, scost, dcost int) int { +// Distance Function that gives Levenshtein Distance +func Distance(str1, str2 string, icost, scost, dcost int) int { row1 := make([]int, len(str2)+1) row2 := make([]int, len(str2)+1) diff --git a/strings/levenshtein_distance/levenshteindistance_test.go b/strings/levenshtein/levenshteindistance_test.go similarity index 84% rename from strings/levenshtein_distance/levenshteindistance_test.go rename to strings/levenshtein/levenshteindistance_test.go index 25537dc98..8e15cd94e 100644 --- a/strings/levenshtein_distance/levenshteindistance_test.go +++ b/strings/levenshtein/levenshteindistance_test.go @@ -1,4 +1,4 @@ -package levenshtein_distance +package levenshtein import "testing" @@ -43,7 +43,7 @@ var testCases = []struct { func TestLevenshteinDistance(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := LevenshteinDistance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) + actual := Distance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost) if actual != tc.expected { t.Errorf("Expected Levenshtein distance between strings: '%s' and '%s' is %v, but got: %v", tc.string1, tc.string2, tc.expected, actual) } diff --git a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go b/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go deleted file mode 100644 index dfbb6ae67..000000000 --- a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick.go +++ /dev/null @@ -1,318 +0,0 @@ -package advancedahocorasick - -import ( - "fmt" - "time" -) - -// User defined. -// Set to true to print various extra stuff out (slows down the execution) -// Set to false for quick and quiet execution. -// const debugMode bool = true // TODO: very convoluted algorithm need time to read through it properly - -// Result structure -type Result struct { - occurrences map[string][]int -} - -// Implementation of Advanced Aho-Corasick algorithm (Prefix based). -// Searches for a set of strings (patterns.txt) in text.txt. -// func main() { -// patFile, err := ioutil.ReadFile("../patterns.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("../text.txt") -// if err != nil { -// log.Fatal(err) -// } -// patterns := strings.Split(string(patFile), " ") -// fmt.Printf("\nRunning: Advanced Aho-Corasick algorithm.\n\n") -// if debugMode == true { -// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) -// } -// for i := 0; i < len(patterns); i++ { -// if len(patterns[i]) > len(textFile) { -// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) -// } -// if debugMode == true { -// fmt.Printf("%q ", patterns[i]) -// } -// } -// if debugMode == true { -// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) -// } -// r := ahoCorasick(string(textFile), patterns) -// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) -// for i := range value { -// fmt.Printf("%d", value[i]) -// if i != len(value)-1 { -// fmt.Printf(", ") -// } -// } -// fmt.Printf(".") -// } -// return -// } - -// AhoCorasick Function performing the Advanced Aho-Corasick alghoritm. -// Finds and prints occurrences of each pattern. -func AhoCorasick(t string, p []string) Result { - startTime := time.Now() - occurrences := make(map[int][]int) - ac, f := BuildExtendedAc(p) - // if debugMode == true { - // fmt.Printf("\n\nAC:\n\n") - // } - current := 0 - for pos := 0; pos < len(t); pos++ { - if GetTransition(current, t[pos], ac) != -1 { - current = GetTransition(current, t[pos], ac) - } else { - current = 0 - } - _, ok := f[current] - if ok { - for i := range f[current] { - if p[f[current][i]] == GetWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match - // if debugMode == true { - // fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) - // } - newOccurrences := IntArrayCapUp(occurrences[f[current][i]]) - occurrences[f[current][i]] = newOccurrences - occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 - } - } - } - } - elapsed := time.Since(startTime) - fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - - var resultOccurrences = make(map[string][]int) - for key, value := range occurrences { - resultOccurrences[p[key]] = value - } - - return Result{ - resultOccurrences, - } -} - -// BuildExtendedAc Functions that builds extended Aho Corasick automaton. -func BuildExtendedAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int) { - acTrie, stateIsTerminal, f := ConstructTrie(p) - s := make([]int, len(stateIsTerminal)) //supply function - i := 0 //root of acTrie - acToReturn = acTrie - s[i] = -1 - // if debugMode == true { - // fmt.Printf("\n\nAC construction: \n") - // } - for current := 1; current < len(stateIsTerminal); current++ { - o, parent := GetParent(current, acTrie) - down := s[parent] - for StateExists(down, acToReturn) && GetTransition(down, o, acToReturn) == -1 { - down = s[down] - } - if StateExists(down, acToReturn) { - s[current] = GetTransition(down, o, acToReturn) - if stateIsTerminal[s[current]] { - stateIsTerminal[current] = true - f[current] = ArrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) - // if debugMode == true { - // fmt.Printf(" f[%d] set to: ", current) - // for i := range f[current] { - // fmt.Printf("%d\n", f[current][i]) - // } - // } - } - } else { - s[current] = i //initial state? - } - } - // if debugMode == true { - // fmt.Printf("\nsupply function: \n") - // for i := range s { - // fmt.Printf("\ns[%d]=%d", i, s[i]) - // } - // fmt.Printf("\n\n") - // for i, j := range f { - // fmt.Printf("f[%d]=", i) - // for k := range j { - // fmt.Printf("%d\n", j[k]) - // } - // } - // } - // if debugMode == true { - // fmt.Printf("\n\nAdAC completion: \n") - // } - // advanced Aho-Corasick part - a := ComputeAlphabet(p) // concat of all patterns in p - for j := range a { - if GetTransition(i, a[j], acToReturn) == -1 { - CreateTransition(i, a[j], i, acToReturn) - } - } - for current := 1; current < len(stateIsTerminal); current++ { - for j := range a { - if GetTransition(current, a[j], acToReturn) == -1 { - CreateTransition(current, a[j], GetTransition(s[current], a[j], acToReturn), acToReturn) - } - } - } - return acToReturn, f -} - -// ConstructTrie Function that constructs Trie as an automaton for a set of reversed & trimmed strings. -func ConstructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { - trie = make(map[int]map[uint8]int) - stateIsTerminal = make([]bool, 1) - f = make(map[int][]int) - state := 1 - // if debugMode == true { - // fmt.Printf("\n\nTrie construction: \n") - // } - CreateNewState(0, trie) - for i := 0; i < len(p); i++ { - current := 0 - j := 0 - for j < len(p[i]) && GetTransition(current, p[i][j], trie) != -1 { - current = GetTransition(current, p[i][j], trie) - j++ - } - for j < len(p[i]) { - stateIsTerminal = BoolArrayCapUp(stateIsTerminal) - CreateNewState(state, trie) - stateIsTerminal[state] = false - CreateTransition(current, p[i][j], state, trie) - current = state - j++ - state++ - } - if stateIsTerminal[current] { - newArray := IntArrayCapUp(f[current]) - newArray[len(newArray)-1] = i - f[current] = newArray // F(Current) <- F(Current) union {i} - // if debugMode == true { - // fmt.Printf(" and %d", i) - // } - } else { - stateIsTerminal[current] = true - f[current] = []int{i} // F(Current) <- {i} - // if debugMode == true { - // fmt.Printf("\n%d is terminal for word number %d", current, i) - // } - } - } - return trie, stateIsTerminal, f -} - -// Contains Returns 'true' if arry of int's 's' contains int 'e', 'false' otherwise. -func Contains(s []int, e int) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -// GetWord Function that returns word found in text 't' at position range 'begin' to 'end'. -func GetWord(begin, end int, t string) string { - for end >= len(t) { - return "" - } - d := make([]uint8, end-begin+1) - for j, i := 0, begin; i <= end; i, j = i+1, j+1 { - d[j] = t[i] - } - return string(d) -} - -// ComputeAlphabet Function that returns string of all the possible characters in given patterns. -func ComputeAlphabet(p []string) (s string) { - s = p[0] - for i := 1; i < len(p); i++ { - s = s + p[i] - } - return s -} - -// IntArrayCapUp Dynamically increases an array size of int's by 1. -func IntArrayCapUp(old []int) (new []int) { - new = make([]int, cap(old)+1) - copy(new, old) //copy(dst,src) - // old = new - return new -} - -// BoolArrayCapUp Dynamically increases an array size of bool's by 1. -func BoolArrayCapUp(old []bool) (new []bool) { - new = make([]bool, cap(old)+1) - copy(new, old) - // old = new - return new -} - -// ArrayUnion Concats two arrays of int's into one. -func ArrayUnion(to, from []int) (concat []int) { - concat = to - for i := range from { - if !Contains(concat, from[i]) { - concat = IntArrayCapUp(concat) - concat[len(concat)-1] = from[i] - } - } - return concat -} - -// GetParent Function that finds the first previous state of a state and returns it. -// Used for trie where there is only one parent. -func GetParent(state int, at map[int]map[uint8]int) (uint8, int) { - for beginState, transitions := range at { - for c, endState := range transitions { - if endState == state { - return c, beginState - } - } - } - return 0, 0 //unreachable -} - -// CreateNewState Automaton function for creating a new state 'state'. -func CreateNewState(state int, at map[int]map[uint8]int) { - at[state] = make(map[uint8]int) - // if debugMode == true { - // fmt.Printf("\ncreated state %d", state) - // } -} - -// CreateTransition Creates a transition for function σ(state,letter) = end. -func CreateTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { - at[fromState][overChar] = toState - // if debugMode == true { - // fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - // } -} - -// GetTransition Returns ending state for transition σ(fromState,overChar), '-1' if there is none. -func GetTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !StateExists(fromState, at) { - return -1 - } - toState, ok := at[fromState][overChar] - if !ok { - return -1 - } - return toState -} - -// StateExists Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. -func StateExists(state int, at map[int]map[uint8]int) bool { - _, ok := at[state] - if !ok || state == -1 || at[state] == nil { - return false - } - return true -} diff --git a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go b/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go deleted file mode 100644 index a7861858b..000000000 --- a/strings/multiple_string_matching/advanced_aho_corasick/advancedahocorasick_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package advancedahocorasick - -import ( - "fmt" - "reflect" - "strings" - "testing" -) - -var testCases = []struct { - name string - words []string - text string - expected Result -}{ - - { - "String comparison on all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conferenceannounce_announce_annually_announce", - Result{ - map[string][]int{ - "annual": {4, 39}, - "announce": {21, 30, 48}, - "annually": {39}, - }, - }, - }, - { - "String comparison on not all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conference_announce", - Result{ - map[string][]int{ - "annual": {4}, - "announce": {22}, - }, - }, - }, - { - "String comparison on not all patterns found", - []string{"announce", "annual", "annually"}, - "CPM_annual_conference_announce", - Result{ - map[string][]int{ - "annual": {4}, - "announce": {22}, - }, - }, - }, -} - -func TestAhoCorasick(t *testing.T) { - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - actual := AhoCorasick(tc.text, tc.words) - if !reflect.DeepEqual(actual, tc.expected) { - actualString := convertToString(actual) - expectedString := convertToString(tc.expected) - t.Errorf("Expected matches for patterns %s for string '%s' are: patterns and positions found %v, but actual matches are: patterns and positions found %v", - tc.words, tc.text, actualString, expectedString) - } - }) - } -} - -func convertToString(res Result) string { - // var r string - var r strings.Builder - for key, val := range res.occurrences { - r.WriteString(fmt.Sprintf("Word: '%s' at positions: ", key)) - for i := range val { - r.WriteString(fmt.Sprintf("%d", val[i])) - if i != len(val)-1 { - // r = r + fmt.Sprintf(", ") - r.WriteString(", ") - } - } - // r = r + fmt.Sprintf(". ") - r.WriteString(". ") - } - return r.String() -} diff --git a/strings/multiple_string_matching/aho_corasick/ahocorasick.go b/strings/multiple_string_matching/aho_corasick/ahocorasick.go deleted file mode 100644 index 903f693fc..000000000 --- a/strings/multiple_string_matching/aho_corasick/ahocorasick.go +++ /dev/null @@ -1,303 +0,0 @@ -package ahocorasick - -import ( - "fmt" - "time" -) - -// User defined. -// Set to true to print various extra stuff out (slows down the execution) -// Set to false for quick and quiet execution. -// const debugMode bool = true - -type Result struct { - occurrences map[string][]int -} - -// Implementation of Basic Aho-Corasick algorithm (Prefix based). -// Searches for a set of strings (patterns.txt) in text.txt. -// func main() { -// patFile, err := ioutil.ReadFile("../patterns.txt") -// if err != nil { -// log.Fatal(err) -// } -// textFile, err := ioutil.ReadFile("../text.txt") -// if err != nil { -// log.Fatal(err) -// } -// patterns := strings.Split(string(patFile), " ") -// fmt.Printf("\nRunning: Basic Aho-Corasick algorithm.\n\n") -// if debugMode == true { -// fmt.Printf("Searching for %d patterns/words:\n", len(patterns)) -// } -// for i := 0; i < len(patterns); i++ { -// if len(patterns[i]) > len(textFile) { -// log.Fatal("There is a pattern that is longer than text! Pattern number:", i+1) -// } -// if debugMode == true { -// fmt.Printf("%q ", patterns[i]) -// } -// } -// if debugMode == true { -// fmt.Printf("\n\nIn text (%d chars long): \n%q\n\n", len(textFile), textFile) -// } -// r := ahoCorasick(string(textFile), patterns) -// for key, value := range r.occurrences { //prints all occurrences of each pattern (if there was at least one) -// fmt.Printf("\nThere were %d occurrences for word: %q at positions: ", len(value), key) -// for i := range value { -// fmt.Printf("%d", value[i]) -// if i != len(value)-1 { -// fmt.Printf(", ") -// } -// } -// fmt.Printf(".") -// } -// } - -// AhoCorasick Function performing the Basic Aho-Corasick algorithm. -// Finds and prints occurrences of each pattern. -func AhoCorasick(t string, p []string) Result { - startTime := time.Now() - occurrences := make(map[int][]int) - ac, f, s := buildAc(p) - // if debugMode == true { - // fmt.Printf("\n\nAC:\n\n") - // } - current := 0 - for pos := 0; pos < len(t); pos++ { - // if debugMode == true { - // fmt.Printf("Position: %d, we read: %c", pos, t[pos]) - // } - for getTransition(current, t[pos], ac) == -1 && s[current] != -1 { - current = s[current] - } - if getTransition(current, t[pos], ac) != -1 { - current = getTransition(current, t[pos], ac) - fmt.Printf(" (Continue) \n") - } else { - current = 0 - // if debugMode == true { - // fmt.Printf(" (FAIL) \n") - // } - } - _, ok := f[current] - if ok { - for i := range f[current] { - if p[f[current][i]] == getWord(pos-len(p[f[current][i]])+1, pos, t) { //check for word match - // if debugMode == true { - // fmt.Printf("Occurrence at position %d, %q = %q\n", pos-len(p[f[current][i]])+1, p[f[current][i]], p[f[current][i]]) - // } - newOccurrences := intArrayCapUp(occurrences[f[current][i]]) - occurrences[f[current][i]] = newOccurrences - occurrences[f[current][i]][len(newOccurrences)-1] = pos - len(p[f[current][i]]) + 1 - } - } - } - } - elapsed := time.Since(startTime) - fmt.Printf("\n\nElapsed %f secs\n", elapsed.Seconds()) - var resultOccurrences = make(map[string][]int) - for key, value := range occurrences { - resultOccurrences[p[key]] = value - } - - return Result{ - resultOccurrences, - } -} - -// Functions that builds Aho Corasick automaton. -func buildAc(p []string) (acToReturn map[int]map[uint8]int, f map[int][]int, s []int) { - acTrie, stateIsTerminal, f := constructTrie(p) - s = make([]int, len(stateIsTerminal)) //supply function - i := 0 //root of acTrie - acToReturn = acTrie - s[i] = -1 - // if debugMode == true { - // fmt.Printf("\n\nAC construction: \n") - // } - for current := 1; current < len(stateIsTerminal); current++ { - o, parent := getParent(current, acTrie) - down := s[parent] - for stateExists(down, acToReturn) && getTransition(down, o, acToReturn) == -1 { - down = s[down] - } - if stateExists(down, acToReturn) { - s[current] = getTransition(down, o, acToReturn) - if stateIsTerminal[s[current]] { - stateIsTerminal[current] = true - f[current] = arrayUnion(f[current], f[s[current]]) //F(Current) <- F(Current) union F(S(Current)) - // if debugMode == true { - // fmt.Printf(" f[%d] set to: ", current) - // for i := range f[current] { - // fmt.Printf("%d\n", f[current][i]) - // } - // } - } - } else { - s[current] = i //initial state? - } - } - // if debugMode == true { - // fmt.Printf("\nsupply function: \n") - // for i := range s { - // fmt.Printf("\ns[%d]=%d", i, s[i]) - // } - // fmt.Printf("\n\n") - // for i, j := range f { - // fmt.Printf("f[%d]=", i) - // for k := range j { - // fmt.Printf("%d\n", j[k]) - // } - // } - // } - return acToReturn, f, s -} - -// Function that constructs Trie as an automaton for a set of reversed & trimmed strings. -func constructTrie(p []string) (trie map[int]map[uint8]int, stateIsTerminal []bool, f map[int][]int) { - trie = make(map[int]map[uint8]int) - stateIsTerminal = make([]bool, 1) - f = make(map[int][]int) - state := 1 - // if debugMode == true { - // fmt.Printf("\n\nTrie construction: \n") - // } - createNewState(0, trie) - for i := 0; i < len(p); i++ { - current := 0 - j := 0 - for j < len(p[i]) && getTransition(current, p[i][j], trie) != -1 { - current = getTransition(current, p[i][j], trie) - j++ - } - for j < len(p[i]) { - stateIsTerminal = boolArrayCapUp(stateIsTerminal) - createNewState(state, trie) - stateIsTerminal[state] = false - createTransition(current, p[i][j], state, trie) - current = state - j++ - state++ - } - if stateIsTerminal[current] { - newArray := intArrayCapUp(f[current]) - newArray[len(newArray)-1] = i - f[current] = newArray //F(Current) <- F(Current) union {i} - // if debugMode == true { - // fmt.Printf(" and %d", i) - // } - } else { - stateIsTerminal[current] = true - f[current] = []int{i} //F(Current) <- {i} - // if debugMode == true { - // fmt.Printf("\n%d is terminal for word number %d", current, i) - // } - } - } - return trie, stateIsTerminal, f -} - -/** -Returns 'true' if array of int's 's' contains int 'e', 'false' otherwise. - -@author Mostafa http://stackoverflow.com/a/10485970 -*/ -func contains(s []int, e int) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -// Function that returns word found in text 't' at position range 'begin' to 'end'. -func getWord(begin, end int, t string) string { - for end >= len(t) { - return "" - } - d := make([]uint8, end-begin+1) - for j, i := 0, begin; i <= end; i, j = i+1, j+1 { - d[j] = t[i] - } - return string(d) -} - -// Dynamically increases an array size of int's by 1. -func intArrayCapUp(old []int) (new []int) { - new = make([]int, cap(old)+1) - copy(new, old) //copy(dst,src) - // old = new - return new -} - -// Dynamically increases an array size of bool's by 1. -func boolArrayCapUp(old []bool) (new []bool) { - new = make([]bool, cap(old)+1) - copy(new, old) - // old = new - return new -} - -// Concats two arrays of int's into one. -func arrayUnion(to, from []int) (concat []int) { - concat = to - for i := range from { - if !contains(concat, from[i]) { - concat = intArrayCapUp(concat) - concat[len(concat)-1] = from[i] - } - } - return concat -} - -// Function that finds the first previous state of a state and returns it. -// Used for trie where there is only one parent. -func getParent(state int, at map[int]map[uint8]int) (uint8, int) { - for beginState, transitions := range at { - for c, endState := range transitions { - if endState == state { - return c, beginState - } - } - } - return 0, 0 //unreachable -} - -// Automaton function for creating a new state 'state'. -func createNewState(state int, at map[int]map[uint8]int) { - at[state] = make(map[uint8]int) - // if debugMode == true { - // fmt.Printf("\ncreated state %d", state) - // } -} - -// Creates a transition for function σ(state,letter) = end. -func createTransition(fromState int, overChar uint8, toState int, at map[int]map[uint8]int) { - at[fromState][overChar] = toState - // if debugMode == true { - // fmt.Printf("\n σ(%d,%c)=%d;", fromState, overChar, toState) - // } -} - -// Returns ending state for transition σ(fromState,overChar), '-1' if there is none. -func getTransition(fromState int, overChar uint8, at map[int]map[uint8]int) (toState int) { - if !stateExists(fromState, at) { - return -1 - } - toState, ok := at[fromState][overChar] - if !ok { - return -1 - } - return toState -} - -// Checks if state 'state' exists. Returns 'true' if it does, 'false' otherwise. -func stateExists(state int, at map[int]map[uint8]int) bool { - _, ok := at[state] - if !ok || state == -1 || at[state] == nil { - return false - } - return true -} diff --git a/strings/naive_string_search/naivestringsearch.go b/strings/search/patternsearch.go similarity index 85% rename from strings/naive_string_search/naivestringsearch.go rename to strings/search/patternsearch.go index 3aa9692a6..ca75129a4 100644 --- a/strings/naive_string_search/naivestringsearch.go +++ b/strings/search/patternsearch.go @@ -8,9 +8,9 @@ Time Complexity : O(n*m) m = length of pattern */ -package naive_string_search +package search -func naivePatternSearch(text string, pattern string) []int { +func Naive(text string, pattern string) []int { var positions []int for i := 0; i <= len(text)-len(pattern); i++ { var match bool = true diff --git a/strings/naive_string_search/naivestringsearch_test.go b/strings/search/patternsearch_test.go similarity index 85% rename from strings/naive_string_search/naivestringsearch_test.go rename to strings/search/patternsearch_test.go index 89db92958..2df0b842c 100644 --- a/strings/naive_string_search/naivestringsearch_test.go +++ b/strings/search/patternsearch_test.go @@ -1,4 +1,4 @@ -package naive_string_search +package search import ( "reflect" @@ -37,10 +37,10 @@ var testCases = []struct { }, } -func TestNaivePatternSearch(t *testing.T) { +func TestNaive(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := naivePatternSearch(tc.input, tc.pattern) + actual := Naive(tc.input, tc.pattern) if !reflect.DeepEqual(actual, tc.expected) { t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v, but actual matches are: %v", tc.pattern, tc.input, tc.expected, actual) } diff --git a/strings/single_string_matching/pattern.txt b/strings/single_string_matching/pattern.txt deleted file mode 100644 index 487161401..000000000 --- a/strings/single_string_matching/pattern.txt +++ /dev/null @@ -1 +0,0 @@ -announce \ No newline at end of file diff --git a/strings/single_string_matching/text.txt b/strings/single_string_matching/text.txt deleted file mode 100644 index e98cf5c73..000000000 --- a/strings/single_string_matching/text.txt +++ /dev/null @@ -1 +0,0 @@ -CPM_annual_conference_announce \ No newline at end of file diff --git a/data_structures/avl/avl.go b/structure/avl/avl.go similarity index 100% rename from data_structures/avl/avl.go rename to structure/avl/avl.go diff --git a/data_structures/avl/avl_test.go b/structure/avl/avl_test.go similarity index 100% rename from data_structures/avl/avl_test.go rename to structure/avl/avl_test.go diff --git a/data_structures/binary_tree/btree.go b/structure/binarytree/btree.go similarity index 100% rename from data_structures/binary_tree/btree.go rename to structure/binarytree/btree.go diff --git a/data_structures/binary_tree/node.go b/structure/binarytree/node.go similarity index 100% rename from data_structures/binary_tree/node.go rename to structure/binarytree/node.go diff --git a/data_structures/dynamic_array/dynamicarray.go b/structure/dynamicarray/dynamicarray.go similarity index 52% rename from data_structures/dynamic_array/dynamicarray.go rename to structure/dynamicarray/dynamicarray.go index 0d09bb8a3..66822be70 100644 --- a/data_structures/dynamic_array/dynamicarray.go +++ b/structure/dynamicarray/dynamicarray.go @@ -1,16 +1,16 @@ -// Dynamic Array -// description: A dynamic array is quite similar to a regular array, but its size is modifiable during program runtime. -// details: for more details check out those links below here: -// geeks for geeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ -// We can mention that Dynamic Array is like Slice for more detail about `Go` Slices check those articles : -// https://blog.golang.org/slices-intro -// https://blog.golang.org/slices +// Package dynamicarray +// A dynamic array is quite similar to a regular array, but its Size is modifiable during program runtime, +// very similar to how a slice in Go works. The implementation is for educational purposes and explains +// how one might go about implementing their own version of slices. +// +// For more details check out those links below here: +// GeeksForGeeks article : https://www.geeksforgeeks.org/how-do-dynamic-arrays-work/ +// Go blog: https://blog.golang.org/slices-intro +// Go blog: https://blog.golang.org/slices // authors [Wesllhey Holanda](https://github.com/wesllhey), [Milad](https://github.com/miraddo) // see dynamicarray.go, dynamicarray_test.go - package dynamicarray -// errors: used to handle CheckRangeFromIndex function with a reasonable error value import ( "errors" ) @@ -18,13 +18,10 @@ import ( var defaultCapacity = 10 // DynamicArray structure -// size: length of array -// capacity: the maximum length of the segment -// elementData: an array of any type of data with interface type DynamicArray struct { - size int - capacity int - elementData []interface{} + Size int + Capacity int + ElementData []interface{} } // Put function is change/update the value in array with the index and new value @@ -35,19 +32,19 @@ func (da *DynamicArray) Put(index int, element interface{}) error { return err } - da.elementData[index] = element + da.ElementData[index] = element return nil } // Add function is add new element to our array func (da *DynamicArray) Add(element interface{}) { - if da.size == da.capacity { + if da.Size == da.Capacity { da.NewCapacity() } - da.elementData[da.size] = element - da.size++ + da.ElementData[da.Size] = element + da.Size++ } // Remove function is remove an element with the index @@ -58,10 +55,10 @@ func (da *DynamicArray) Remove(index int) error { return err } - copy(da.elementData[index:], da.elementData[index+1:da.size]) - da.elementData[da.size-1] = nil + copy(da.ElementData[index:], da.ElementData[index+1:da.Size]) + da.ElementData[da.Size-1] = nil - da.size-- + da.Size-- return nil } @@ -74,38 +71,38 @@ func (da *DynamicArray) Get(index int) (interface{}, error) { return nil, err } - return da.elementData[index], nil + return da.ElementData[index], nil } // IsEmpty function is check that the array has value or not func (da *DynamicArray) IsEmpty() bool { - return da.size == 0 + return da.Size == 0 } // GetData function return all value of array func (da *DynamicArray) GetData() []interface{} { - return da.elementData[:da.size] + return da.ElementData[:da.Size] } // CheckRangeFromIndex function it will check the range from the index func (da *DynamicArray) CheckRangeFromIndex(index int) error { - if index >= da.size || index < 0 { + if index >= da.Size || index < 0 { return errors.New("index out of range") } return nil } -// NewCapacity function increase the capacity +// NewCapacity function increase the Capacity func (da *DynamicArray) NewCapacity() { - if da.capacity == 0 { - da.capacity = defaultCapacity + if da.Capacity == 0 { + da.Capacity = defaultCapacity } else { - da.capacity = da.capacity << 1 + da.Capacity = da.Capacity << 1 } - newDataElement := make([]interface{}, da.capacity) + newDataElement := make([]interface{}, da.Capacity) - copy(newDataElement, da.elementData) + copy(newDataElement, da.ElementData) - da.elementData = newDataElement + da.ElementData = newDataElement } diff --git a/data_structures/dynamic_array/dynamicarray_test.go b/structure/dynamicarray/dynamicarray_test.go similarity index 94% rename from data_structures/dynamic_array/dynamicarray_test.go rename to structure/dynamicarray/dynamicarray_test.go index adb1cd81a..976370ba8 100644 --- a/data_structures/dynamic_array/dynamicarray_test.go +++ b/structure/dynamicarray/dynamicarray_test.go @@ -1,12 +1,10 @@ package dynamicarray -// reflect: used for check equal values import ( "reflect" "testing" ) -// TestDynamicArray some test for dynamic array to make sure everything is ok, and we got the right result func TestDynamicArray(t *testing.T) { numbers := DynamicArray{} diff --git a/data_structures/hashmap/hashmap.go b/structure/hashmap/hashmap.go similarity index 100% rename from data_structures/hashmap/hashmap.go rename to structure/hashmap/hashmap.go diff --git a/data_structures/hashmap/hashmap_test.go b/structure/hashmap/hashmap_test.go similarity index 100% rename from data_structures/hashmap/hashmap_test.go rename to structure/hashmap/hashmap_test.go diff --git a/datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg b/structure/linkedlist/Linked_Cyclic_List.jpg similarity index 100% rename from datastructures/linkedlist/cyclicallylinkedlist/Linked_Cyclic_List.jpg rename to structure/linkedlist/Linked_Cyclic_List.jpg diff --git a/structure/linkedlist/Readme.md b/structure/linkedlist/Readme.md new file mode 100644 index 000000000..32f784c96 --- /dev/null +++ b/structure/linkedlist/Readme.md @@ -0,0 +1,27 @@ +# Linked List +*** +## What is it? +*** +Linked list is a data structure that is a linear chain of data elements whose order is not given by their phyisical placement in memory. This structure is built up of nodes which point to the element ahead or behind this particular node (depending on the type of Linked List). + +# Types of Linked List implemented within this repository + +## Singly Linked List +Singly Linked List is a linked list in which a node only points to the next element. +Some of the main applications of Singly Linked List are in the construction +of fundamental data structures such as Stacks and Queues. + +## Doubly Linked List +Doubly Linked List is a linked list in which a node points to both the element ahead and behind the node. +Any application which requires us to keep track of forward and backward information uses doubly linked list. +For example, the feature of undo and redo are implemented using these doubly linked lists. + +## Cyclic Linked List AKA Looped Linked List +Looped Linked Lists are singly or doubly-linked that chase their own tail: +A points to B, B points to C, C points to D, and D points to A. +They are better suited for cyclic data such as train schedules. +These lists are missing the first and last items. +Therefore, it is necessary to introduce the concept of the current position. + +This picture shows similar lists: +![Alt text](./Linked_Cyclic_List.jpg?raw=true) diff --git a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go b/structure/linkedlist/cyclic.go similarity index 56% rename from datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go rename to structure/linkedlist/cyclic.go index 454088c86..cf0ab22df 100644 --- a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist.go +++ b/structure/linkedlist/cyclic.go @@ -1,49 +1,34 @@ -// Package cyclicallylinkedlist demonstration of Linked List Cycle in golang - -package cyclicallylinkedlist +package linkedlist import "fmt" -// Node of List. -type ClNode struct { - Val interface{} - prev *ClNode - next *ClNode -} - -// The Cycling list in this implementation is addressed -// by means of the element located at the current position. -type ClList struct { - Size int - CurrentItem *ClNode +// Cyclic Struct which cycles the linked list in this implementation. +type Cyclic struct { + Size int + Head *Node } // Create new list. -func NewList() *ClList { - return &ClList{0, nil} -} - -// Create new node. -func NewNode(val interface{}) *ClNode { - return &ClNode{val, nil, nil} +func NewCyclic() *Cyclic { + return &Cyclic{0, nil} } // Inserting the first node is a special case. It will // point to itself. For other cases, the node will be added -// to the end of the list. End of the list is prev field of +// to the end of the list. End of the list is Prev field of // current item. Complexity O(1). -func (cl *ClList) Add(val interface{}) { +func (cl *Cyclic) Add(val interface{}) { n := NewNode(val) cl.Size++ - if cl.CurrentItem == nil { - n.prev = n - n.next = n - cl.CurrentItem = n + if cl.Head == nil { + n.Prev = n + n.Next = n + cl.Head = n } else { - n.prev = cl.CurrentItem.prev - n.next = cl.CurrentItem - cl.CurrentItem.prev.next = n - cl.CurrentItem.prev = n + n.Prev = cl.Head.Prev + n.Next = cl.Head + cl.Head.Prev.Next = n + cl.Head.Prev = n } } @@ -61,7 +46,7 @@ func (cl *ClList) Add(val interface{}) { // places is the same as moving N - P places back. // Therefore, if P > N / 2, you can turn the list by N-P places back. // Complexity O(n). -func (cl *ClList) Rotate(places int) { +func (cl *Cyclic) Rotate(places int) { if cl.Size > 0 { if places < 0 { multiple := cl.Size - 1 - places/cl.Size @@ -72,13 +57,13 @@ func (cl *ClList) Rotate(places int) { if places > cl.Size/2 { places = cl.Size - places for i := 0; i < places; i++ { - cl.CurrentItem = cl.CurrentItem.prev + cl.Head = cl.Head.Prev } } else if places == 0 { return } else { for i := 0; i < places; i++ { - cl.CurrentItem = cl.CurrentItem.next + cl.Head = cl.Head.Next } } @@ -86,25 +71,25 @@ func (cl *ClList) Rotate(places int) { } // Delete the current item. -func (cl *ClList) Delete() bool { +func (cl *Cyclic) Delete() bool { var deleted bool - var prevItem, thisItem, nextItem *ClNode + var prevItem, thisItem, nextItem *Node if cl.Size == 0 { return deleted } deleted = true - thisItem = cl.CurrentItem - nextItem = thisItem.next - prevItem = thisItem.prev + thisItem = cl.Head + nextItem = thisItem.Next + prevItem = thisItem.Prev if cl.Size == 1 { - cl.CurrentItem = nil + cl.Head = nil } else { - cl.CurrentItem = nextItem - nextItem.prev = prevItem - prevItem.next = nextItem + cl.Head = nextItem + nextItem.Prev = prevItem + prevItem.Next = nextItem } cl.Size-- @@ -112,33 +97,33 @@ func (cl *ClList) Delete() bool { } // Destroy all items in the list. -func (cl *ClList) Destroy() { +func (cl *Cyclic) Destroy() { for cl.Delete() { continue } } // Show list body. -func (cl *ClList) Walk() *ClNode { - var start *ClNode - start = cl.CurrentItem +func (cl *Cyclic) Walk() *Node { + var start *Node + start = cl.Head for i := 0; i < cl.Size; i++ { fmt.Printf("%v \n", start.Val) - start = start.next + start = start.Next } return start } // https://en.wikipedia.org/wiki/Josephus_problem // This is a struct-based solution for Josephus problem. -func JosephusProblem(cl *ClList, k int) int { +func JosephusProblem(cl *Cyclic, k int) int { for cl.Size > 1 { cl.Rotate(k) cl.Delete() cl.Rotate(-1) } - retval := cl.CurrentItem.Val.(int) + retval := cl.Head.Val.(int) cl.Destroy() return retval } diff --git a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go b/structure/linkedlist/cyclic_test.go similarity index 84% rename from datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go rename to structure/linkedlist/cyclic_test.go index 10eb1f88c..162f9d0a1 100644 --- a/datastructures/linkedlist/cyclicallylinkedlist/cyclicallylinkedlist_test.go +++ b/structure/linkedlist/cyclic_test.go @@ -1,28 +1,28 @@ -package cyclicallylinkedlist +package linkedlist import ( "reflect" "testing" ) -func fillList(list *ClList, n int) { +func fillList(list *Cyclic, n int) { for i := 1; i <= n; i++ { list.Add(i) } } func TestAdd(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) want := []interface{}{1, 2, 3} var got []interface{} - var start *ClNode - start = list.CurrentItem + var start *Node + start = list.Head for i := 0; i < list.Size; i++ { got = append(got, start.Val) - start = start.next + start = start.Next } if !reflect.DeepEqual(got, want) { t.Errorf("got: %v, want: %v", got, want) @@ -30,7 +30,7 @@ func TestAdd(t *testing.T) { } func TestWalk(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) want := 1 @@ -46,7 +46,7 @@ func TestRotate(t *testing.T) { param int wantToReturn int } - list := NewList() + list := NewCyclic() fillList(list, 3) testCases := []testCase{ @@ -61,7 +61,7 @@ func TestRotate(t *testing.T) { } for idx, tCase := range testCases { list.Rotate(tCase.param) - got := list.CurrentItem.Val + got := list.Head.Val if got != tCase.wantToReturn { t.Errorf("got: %v, want: %v for test id %v", got, tCase.wantToReturn, idx) } @@ -69,13 +69,13 @@ func TestRotate(t *testing.T) { } func TestDelete(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) want := 2 wantSize := 2 list.Delete() - got := list.CurrentItem.Val + got := list.Head.Val if want != got { t.Errorf("got: %v, want: %v", got, want) } @@ -85,12 +85,12 @@ func TestDelete(t *testing.T) { } func TestDestroy(t *testing.T) { - list := NewList() + list := NewCyclic() fillList(list, 3) wantSize := 0 list.Destroy() - got := list.CurrentItem + got := list.Head if got != nil { t.Errorf("got: %v, want: nil", got) @@ -119,7 +119,7 @@ func TestJosephusProblem(t *testing.T) { } for _, tCase := range testCases { - list := NewList() + list := NewCyclic() fillList(list, tCase.listCount) got := JosephusProblem(list, tCase.param) if got != tCase.wantToReturn { diff --git a/structure/linkedlist/doc.go b/structure/linkedlist/doc.go new file mode 100644 index 000000000..580adf068 --- /dev/null +++ b/structure/linkedlist/doc.go @@ -0,0 +1,2 @@ +// Package linkedlist demonstates different implementations on linkedlists. +package linkedlist diff --git a/structure/linkedlist/doubly.go b/structure/linkedlist/doubly.go new file mode 100644 index 000000000..b0c1970f3 --- /dev/null +++ b/structure/linkedlist/doubly.go @@ -0,0 +1,142 @@ +package linkedlist + +import "fmt" + +// Doubly structure with just the Head Node +// We call it `Doubly` to make it easier to +// understand when calling this in peoples +// own local code to understand and experiment +// with this easily. +// For example, we can use gotools `go get` command to get +// this repository cloned inside the +// $GOPATH/src/github.com/TheAlgorithms/Go (you can do this +// manually as well) and use the import statement as follows: +// +// `import "github.com/TheAlgorithms/Go/structure/linkedlist"` +// +// and call linkedlist.Doubly to create a new doubly linked list. +type Doubly struct { + Head *Node +} + +func NewDoubly() *Doubly { + return &Doubly{nil} +} + +// AddAtBeg Add a node to the beginning of the linkedlist +func (ll *Doubly) AddAtBeg(val interface{}) { + n := NewNode(val) + n.Next = ll.Head + + if ll.Head != nil { + ll.Head.Prev = n + } + + ll.Head = n + +} + +// AddAtEnd Add a node at the end of the linkedlist +func (ll *Doubly) AddAtEnd(val interface{}) { + n := NewNode(val) + + if ll.Head == nil { + ll.Head = n + return + } + + cur := ll.Head + for ; cur.Next != nil; cur = cur.Next { + } + cur.Next = n + n.Prev = cur +} + +// DelAtBeg Delete the node at the beginning of the linkedlist +func (ll *Doubly) DelAtBeg() interface{} { + if ll.Head == nil { + return -1 + } + + cur := ll.Head + ll.Head = cur.Next + + if ll.Head != nil { + ll.Head.Prev = nil + } + return cur.Val +} + +// DetAtEnd Delete a node at the end of the linkedlist +func (ll *Doubly) DelAtEnd() interface{} { + // no item + if ll.Head == nil { + return -1 + } + + // only one item + if ll.Head.Next == nil { + return ll.DelAtBeg() + } + + // more than one, go to second last + cur := ll.Head + for ; cur.Next.Next != nil; cur = cur.Next { + } + + retval := cur.Next.Val + cur.Next = nil + return retval +} + +// Count Number of nodes in the linkedlist +func (ll *Doubly) Count() interface{} { + var ctr int = 0 + + for cur := ll.Head; cur != nil; cur = cur.Next { + ctr += 1 + } + + return ctr +} + +// Reverse Reverse the order of the linkedlist +func (ll *Doubly) Reverse() { + var Prev, Next *Node + cur := ll.Head + + for cur != nil { + Next = cur.Next + cur.Next = Prev + cur.Prev = Next + Prev = cur + cur = Next + } + + ll.Head = Prev +} + +// Display diplay the linked list +func (ll *Doubly) Display() { + for cur := ll.Head; cur != nil; cur = cur.Next { + fmt.Print(cur.Val, " ") + } + + fmt.Print("\n") +} + +// DisplayReverse Display the linkedlist in reverse order +func (ll *Doubly) DisplayReverse() { + if ll.Head == nil { + return + } + var cur *Node + for cur = ll.Head; cur.Next != nil; cur = cur.Next { + } + + for ; cur != nil; cur = cur.Prev { + fmt.Print(cur.Val, " ") + } + + fmt.Print("\n") +} diff --git a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go b/structure/linkedlist/doubly_test.go similarity index 65% rename from data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go rename to structure/linkedlist/doubly_test.go index eeac97e87..b46474d48 100644 --- a/data_structures/linkedlist/doubly_linkedlist/doublylinkedlist_test.go +++ b/structure/linkedlist/doubly_test.go @@ -1,12 +1,12 @@ -package doubly_linkedlist +package linkedlist import ( "reflect" "testing" ) -func TestDoubleLinkedList(t *testing.T) { - newList := DoubleLinkedList{} +func TestDoubly(t *testing.T) { + newList := NewDoubly() newList.AddAtBeg(1) newList.AddAtBeg(2) @@ -17,27 +17,27 @@ func TestDoubleLinkedList(t *testing.T) { wantPrev := []int{1, 2, 3} got := []int{} - // check from next address - current := newList.head + // check from Next address + current := newList.Head - got = append(got, current.val) + got = append(got, current.Val.(int)) - for current.next != nil { - current = current.next - got = append(got, current.val) + for current.Next != nil { + current = current.Next + got = append(got, current.Val.(int)) } if !reflect.DeepEqual(got, wantNext) { t.Errorf("got: %v, want: %v", got, wantNext) } - // check from prev address + // check from Prev address got = []int{} - got = append(got, current.val) + got = append(got, current.Val.(int)) - for current.prev != nil { - current = current.prev - got = append(got, current.val) + for current.Prev != nil { + current = current.Prev + got = append(got, current.Val.(int)) } if !reflect.DeepEqual(got, wantPrev) { @@ -50,11 +50,11 @@ func TestDoubleLinkedList(t *testing.T) { t.Run("Test AddAtEnd", func(t *testing.T) { want := []int{3, 2, 1, 4} got := []int{} - current := newList.head - got = append(got, current.val) - for current.next != nil { - current = current.next - got = append(got, current.val) + current := newList.Head + got = append(got, current.Val.(int)) + for current.Next != nil { + current = current.Next + got = append(got, current.Val.(int)) } if !reflect.DeepEqual(got, want) { t.Errorf("got: %v, want: %v", got, want) diff --git a/structure/linkedlist/shared.go b/structure/linkedlist/shared.go new file mode 100644 index 000000000..b9d228f6f --- /dev/null +++ b/structure/linkedlist/shared.go @@ -0,0 +1,14 @@ +package linkedlist + +// Node Structure representing the linkedlist node. +// This node is shared accross different implementations. +type Node struct { + Val interface{} + Prev *Node + Next *Node +} + +// Create new node. +func NewNode(val interface{}) *Node { + return &Node{val, nil, nil} +} diff --git a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go b/structure/linkedlist/singlylinkedlist.go similarity index 60% rename from data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go rename to structure/linkedlist/singlylinkedlist.go index 11267a9a6..cf69056a1 100644 --- a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist.go +++ b/structure/linkedlist/singlylinkedlist.go @@ -1,33 +1,24 @@ -// Package singlelinkedlist Single Linked List -package singly_linkedlist +package linkedlist // demonstration of singly linked list in golang import "fmt" -// TODO: This is not how it should be done but I don't see a way out of this -type snode struct { - Val interface{} - Next *snode -} - -// SingleLinkedList structure with length of the list and its head -type SingleLinkedList struct { +// Singly structure with length of the list and its head +type Singly struct { length int - Head *snode -} -// CreateList returns a new instance of a linked list -func CreateList() *SingleLinkedList { - return &SingleLinkedList{} + // Note that Node here holds both Next and Prev Node + // however only the Next node is used in Singly methods. + Head *Node } -// to avoid mistakes when using pointer vs struct for new snode creation -func NewNode(val interface{}) *snode { - return &snode{val, nil} +// NewSingly returns a new instance of a linked list +func NewSingly() *Singly { + return &Singly{} } // AddAtBeg adds a new snode with given value at the beginning of the list. -func (ll *SingleLinkedList) AddAtBeg(val interface{}) { +func (ll *Singly) AddAtBeg(val interface{}) { n := NewNode(val) n.Next = ll.Head ll.Head = n @@ -35,7 +26,7 @@ func (ll *SingleLinkedList) AddAtBeg(val interface{}) { } // AddAtEnd adds a new snode with given value at the end of the list. -func (ll *SingleLinkedList) AddAtEnd(val int) { +func (ll *Singly) AddAtEnd(val int) { n := NewNode(val) if ll.Head == nil { @@ -52,7 +43,7 @@ func (ll *SingleLinkedList) AddAtEnd(val int) { } // DelAtBeg deletes the snode at the head(beginning) of the list and returns its value. Returns -1 if the list is empty. -func (ll *SingleLinkedList) DelAtBeg() interface{} { +func (ll *Singly) DelAtBeg() interface{} { if ll.Head == nil { return -1 } @@ -65,7 +56,7 @@ func (ll *SingleLinkedList) DelAtBeg() interface{} { } // DelAtEnd deletes the snode at the tail(end) of the list and returns its value. Returns -1 if the list is empty. -func (ll *SingleLinkedList) DelAtEnd() interface{} { +func (ll *Singly) DelAtEnd() interface{} { if ll.Head == nil { return -1 } @@ -87,13 +78,13 @@ func (ll *SingleLinkedList) DelAtEnd() interface{} { } // Count returns the current size of the list. -func (ll *SingleLinkedList) Count() int { +func (ll *Singly) Count() int { return ll.length } // Reverse reverses the list. -func (ll *SingleLinkedList) Reverse() { - var prev, Next *snode +func (ll *Singly) Reverse() { + var prev, Next *Node cur := ll.Head for cur != nil { @@ -107,7 +98,7 @@ func (ll *SingleLinkedList) Reverse() { } // Display prints out the elements of the list. -func (ll *SingleLinkedList) Display() { +func (ll *Singly) Display() { for cur := ll.Head; cur != nil; cur = cur.Next { fmt.Print(cur.Val, " ") } diff --git a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go b/structure/linkedlist/singlylinkedlist_test.go similarity index 93% rename from data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go rename to structure/linkedlist/singlylinkedlist_test.go index 7cd713fd4..0da92cadf 100644 --- a/data_structures/linkedlist/singly_linkedlist/singlylinkedlist_test.go +++ b/structure/linkedlist/singlylinkedlist_test.go @@ -1,12 +1,12 @@ -package singly_linkedlist +package linkedlist import ( "reflect" "testing" ) -func TestLinkedList(t *testing.T) { - list := CreateList() +func TestSingly(t *testing.T) { + list := NewSingly() list.AddAtBeg(1) list.AddAtBeg(2) list.AddAtBeg(3) diff --git a/data_structures/queue/queue_test.go b/structure/queue/queue_test.go similarity index 100% rename from data_structures/queue/queue_test.go rename to structure/queue/queue_test.go diff --git a/data_structures/queue/queuearray.go b/structure/queue/queuearray.go similarity index 100% rename from data_structures/queue/queuearray.go rename to structure/queue/queuearray.go diff --git a/data_structures/queue/queuelinkedlist.go b/structure/queue/queuelinkedlist.go similarity index 100% rename from data_structures/queue/queuelinkedlist.go rename to structure/queue/queuelinkedlist.go diff --git a/data_structures/queue/queuelinklistwithlist.go b/structure/queue/queuelinklistwithlist.go similarity index 100% rename from data_structures/queue/queuelinklistwithlist.go rename to structure/queue/queuelinklistwithlist.go diff --git a/data_structures/set/set.go b/structure/set/set.go similarity index 100% rename from data_structures/set/set.go rename to structure/set/set.go diff --git a/data_structures/stack/stack_test.go b/structure/stack/stack_test.go similarity index 100% rename from data_structures/stack/stack_test.go rename to structure/stack/stack_test.go diff --git a/data_structures/stack/stackarray.go b/structure/stack/stackarray.go similarity index 100% rename from data_structures/stack/stackarray.go rename to structure/stack/stackarray.go diff --git a/data_structures/stack/stacklinkedlist.go b/structure/stack/stacklinkedlist.go similarity index 100% rename from data_structures/stack/stacklinkedlist.go rename to structure/stack/stacklinkedlist.go diff --git a/data_structures/stack/stacklinkedlistwithlist.go b/structure/stack/stacklinkedlistwithlist.go similarity index 100% rename from data_structures/stack/stacklinkedlistwithlist.go rename to structure/stack/stacklinkedlistwithlist.go diff --git a/data_structures/trie/trie.go b/structure/trie/trie.go similarity index 100% rename from data_structures/trie/trie.go rename to structure/trie/trie.go diff --git a/data_structures/trie/trie_test.go b/structure/trie/trie_test.go similarity index 100% rename from data_structures/trie/trie_test.go rename to structure/trie/trie_test.go