- test/ -- папка с файлами для тестов каждой структуры - pkg/ -- папка с реализациями и вспомогательными модулями
243 lines
4.4 KiB
Go
243 lines
4.4 KiB
Go
package hash_table
|
||
|
||
import (
|
||
"bufio"
|
||
"fmt"
|
||
"os"
|
||
)
|
||
|
||
// HashTable - хеш-таблица с цепочками
|
||
type HashTable struct {
|
||
buckets []*bucket
|
||
size int
|
||
capacity int
|
||
loadFactor float64
|
||
}
|
||
|
||
type bucket struct {
|
||
head *elementHT
|
||
}
|
||
|
||
type elementHT struct {
|
||
name string
|
||
phone string
|
||
next *elementHT
|
||
}
|
||
|
||
// NewHashTable - создает новую хеш-таблицу
|
||
func NewHashTable(capacity int, loadFactor float64) *HashTable {
|
||
|
||
buckets := make([]*bucket, capacity)
|
||
|
||
for i := 0; i < capacity; i++ {
|
||
buckets[i] = &bucket{}
|
||
}
|
||
|
||
return &HashTable{
|
||
buckets: buckets,
|
||
size: 0,
|
||
capacity: capacity,
|
||
loadFactor: loadFactor,
|
||
}
|
||
}
|
||
|
||
// func (h HashTable) getIndex(name string) int {
|
||
// return GetHashString(name) % h.size
|
||
// }
|
||
|
||
// func (h HashTable) Add(name string) {
|
||
|
||
// }
|
||
|
||
func (ht *HashTable) GetIndex(name string) int {
|
||
hash := GetHashString(name)
|
||
return hash % ht.capacity
|
||
}
|
||
|
||
// func (ht *HashTable) getIndex(hash int) int {
|
||
// return hash % ht.capacity
|
||
// }
|
||
|
||
func (h *HashTable) Put(name string, phone string) {
|
||
|
||
if h.size >= int(float64(h.capacity)*h.loadFactor) {
|
||
h.resize()
|
||
}
|
||
|
||
ind := h.GetIndex(name)
|
||
|
||
buck := h.buckets[ind]
|
||
|
||
current := buck.head
|
||
|
||
for current != nil {
|
||
if current.name == name {
|
||
current.phone = phone
|
||
return
|
||
}
|
||
|
||
current = current.next
|
||
}
|
||
|
||
newHead := &elementHT{
|
||
name: name,
|
||
phone: phone,
|
||
next: buck.head,
|
||
}
|
||
|
||
buck.head = newHead
|
||
h.size++
|
||
}
|
||
|
||
func (h *HashTable) Get(name string) (phone string, status bool) {
|
||
ind := h.GetIndex(name)
|
||
|
||
buck := h.buckets[ind]
|
||
|
||
current := buck.head
|
||
|
||
for current != nil {
|
||
if current.name == name {
|
||
return current.phone, true
|
||
}
|
||
|
||
current = current.next
|
||
}
|
||
|
||
return "", false
|
||
}
|
||
|
||
func pressEnterToContinue() {
|
||
fmt.Print("Нажмите Enter для продолжения...")
|
||
bufio.NewReader(os.Stdin).ReadBytes('\n')
|
||
}
|
||
|
||
// resize - увеличивает размер таблицы
|
||
func (ht *HashTable) resize() {
|
||
|
||
// fmt.Printf("Resize table!\n elements: %d(%.3f%%)\n old capacity: %d\n new capacity: %d\n", ht.size, float64(ht.size)/float64(ht.capacity), ht.capacity, 2*ht.capacity)
|
||
|
||
// ht.Print()
|
||
|
||
// pressEnterToContinue()
|
||
|
||
newCapacity := ht.capacity * 2
|
||
newHT := NewHashTable(newCapacity, ht.loadFactor)
|
||
|
||
for _, b := range ht.buckets {
|
||
current := b.head
|
||
for current != nil {
|
||
newHT.Put(current.name, current.phone)
|
||
current = current.next
|
||
}
|
||
}
|
||
|
||
ht.buckets = newHT.buckets
|
||
ht.capacity = newCapacity
|
||
}
|
||
|
||
func (ht *HashTable) Remove(name string) bool {
|
||
ind := ht.GetIndex(name)
|
||
|
||
buck := ht.buckets[ind]
|
||
|
||
if buck.head == nil {
|
||
return false
|
||
}
|
||
|
||
if buck.head.name == name {
|
||
buck.head = buck.head.next
|
||
ht.size--
|
||
return true
|
||
}
|
||
|
||
prev := buck.head
|
||
current := buck.head.next
|
||
|
||
for current != nil {
|
||
if current.name == name {
|
||
prev.next = current.next
|
||
ht.size--
|
||
return true
|
||
}
|
||
prev = current
|
||
current = current.next
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
func (ht *HashTable) Contains(name string) bool {
|
||
_, ok := ht.Get(name)
|
||
return ok
|
||
}
|
||
|
||
func (elem *elementHT) ToString() string {
|
||
if elem == nil {
|
||
return "nil"
|
||
}
|
||
|
||
return fmt.Sprintf("Имя: %s, Телефон: %s", elem.name, elem.phone)
|
||
}
|
||
|
||
func (ht *HashTable) Print() {
|
||
for ind := 0; ind < ht.capacity; ind++ {
|
||
buck := ht.buckets[ind]
|
||
current := buck.head
|
||
|
||
bucketsStr := ""
|
||
|
||
for current != nil {
|
||
bucketsStr += " --> " + current.ToString()
|
||
current = current.next
|
||
}
|
||
fmt.Printf("[%d]: %s\n", ind, bucketsStr)
|
||
}
|
||
}
|
||
|
||
func (ht *HashTable) listAll() []elementHT {
|
||
data := make([]elementHT, ht.size)
|
||
|
||
index := 0
|
||
|
||
for ind := 0; ind < ht.capacity; ind++ {
|
||
buck := ht.buckets[ind]
|
||
current := buck.head
|
||
|
||
for current != nil {
|
||
data[index] = elementHT{
|
||
name: current.name,
|
||
phone: current.phone,
|
||
}
|
||
index++
|
||
// fmt.Println(current.name, current.phone)
|
||
current = current.next
|
||
}
|
||
}
|
||
|
||
return data
|
||
}
|
||
|
||
func (ht *HashTable) ListAll() []elementHT {
|
||
// fmt.Printf("Size: %d, Capacity: %d\n", ht.size, ht.capacity)
|
||
data := ht.listAll()
|
||
|
||
data = QSortElementsHT(data, 0, len(data)-1)
|
||
|
||
// for i, el := range data {
|
||
// fmt.Printf("[%d]: \"%s\", %d\n", i, el.name, el.phone)
|
||
// }
|
||
return data
|
||
}
|
||
|
||
// func (ht *HashTable) PrintMostPopularnames(phone int) {
|
||
// // fmt.Printf("Size: %d, Capacity: %d\n", ht.size, ht.capacity)
|
||
// data := ht.listAll()
|
||
|
||
// data = QSortElementsHT(data, 0, len(data)-1)
|
||
|
||
// for i := 0; i < phone; i++ {
|
||
// fmt.Printf("[%d]: %3d : %s\n", i, ht.GetIndex(data[len(data)-i-1].name), data[len(data)-i-1].ToString())
|
||
// }
|
||
// }
|