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())
|
|||
|
|
// }
|
|||
|
|
// }
|