package main import ( "fmt" "math/rand" csvwriter "source/pkg/csv_writer" ds "source/pkg/data_struct" dg "source/pkg/gen_data" bst "source/pkg/structures/bin_search_tree" ht "source/pkg/structures/hash_table" ll "source/pkg/structures/linked_list" // csv "source/pkg/csv_ri" "time" ) const ( countUsers = 20_000 countRepeat = 20 countRandomSearch = 1000 countNotExitstSearch = 500 countDeletes = 1000 ) type TestData struct { Items []ds.MyData // все записи ItemsSorted []ds.MyData // все записи отсортированные Search []ds.MyData // для поиска (существующие и несуществующие) ToDelete []ds.MyData // для удаления UniqueItems []ds.MyData // Уникальные элементы для тестов } type DataStructure interface { Insert(data ds.MyData) InsertAll(data []ds.MyData) Search(name string) (string, bool) Delete(name string) bool Len() int } // Создатели структур type StructureFactory func() DataStructure func NewLinkedList() DataStructure { return ll.NewLinkedList() } func NewHashTable() DataStructure { return ht.NewHashTable(256, 0.75) } func NewBinSearchTree() DataStructure { return bst.NewBinSearchTree() } func uniqueElements(data []ds.MyData) []ds.MyData { res := make([]ds.MyData, 0, len(data)) for _, el := range data { isUnique := true for _, resEl := range res { if el == resEl { isUnique = false break } } if isUnique { res = append(res, el) } } return res } func GenerateTestData() TestData { items := dg.RecordsShuffled(countUsers) // fmt.Println("isSorted:", isSorted(items)) itemsSort := ds.QSort(items, 0, len(items)-1) uniqueItems := uniqueElements(items) existing := make([]ds.MyData, countRandomSearch) // notExisting := [countNotExitstSearch]ds.MyData{} notExisting := make([]ds.MyData, countNotExitstSearch) toDelete := make([]ds.MyData, countDeletes) countUniq := len(uniqueItems) for i := 0; i < countRandomSearch; i++ { // randInd := rand.Intn(countUsers) randInd := rand.Intn(countUniq) existing[i] = uniqueItems[randInd] // fmt.Println(randInd) } for i := 0; i < countNotExitstSearch; i++ { // randInd := rand.Intn(countUsers) randInd := rand.Intn(10) name := fmt.Sprintf("User_%d", randInd) notExisting[i] = *ds.NewData(name, "") // fmt.Println(randInd) } for _, el := range notExisting { existing = append(existing, el) } // toDelete = make([]ds.MyData, countDeletes) usedIndices := make(map[int]bool) for i := 0; i < countDeletes; i++ { var randInd int for { randInd = rand.Intn(countUniq) if !usedIndices[randInd] { usedIndices[randInd] = true break } } toDelete[i] = uniqueItems[randInd] } return TestData{ Items: items, ItemsSorted: itemsSort, Search: existing, ToDelete: toDelete, UniqueItems: uniqueItems, } } // Тест вставки массива данных (один раз) func testOnesInsert(structure DataStructure, data []ds.MyData) float64 { start := time.Now() for _, item := range data { structure.Insert(item) } return time.Since(start).Seconds() } // Тест поиска массива данных (один раз) func testOnesSearch(structure DataStructure, data []ds.MyData) float64 { start := time.Now() // flag := true for _, item := range data { structure.Search(item.Name) // p, ok := structure.Search(item.Name) // if flag { // flag = ((p == item.Phone) == ok) // } } // fmt.Println(flag) return time.Since(start).Seconds() } // Тест удаления массива данных (один раз) func testOnesDelete(structure DataStructure, data []ds.MyData) float64 { start := time.Now() for _, item := range data { structure.Delete(item.Name) } return time.Since(start).Seconds() } func testForData(nameStruct, mode string, factory StructureFactory, data_insert, data_search, data_delete []ds.MyData) { BenchRes := make([]csvwriter.BenchmarkResult, 0, countRepeat*3+3) // Массив строк отчёта averageTimeInsert := 0. averageTimeSearch := 0. averageTimeDelete := 0. for iteration := 0; iteration < countRepeat; iteration++ { structure := factory() insertTime := testOnesInsert(structure, data_insert) averageTimeInsert += insertTime // Отладочная информация для бинарного дерева (проверка на вырождение) if bst, ok := structure.(*bst.BinSearchTree); ok { fmt.Printf( "Высота дерева: %d, элементов: %d\n", bst.Height(), bst.Len(), ) } BenchRes = append(BenchRes, csvwriter.BenchmarkResult{ Structure: nameStruct, Mode: mode, Operation: "Вставка", Time: insertTime, }) searchTime := testOnesSearch(structure, data_search) averageTimeSearch += searchTime BenchRes = append(BenchRes, csvwriter.BenchmarkResult{ Structure: nameStruct, Mode: mode, Operation: "Поиск", Time: searchTime, }) deleteTime := testOnesDelete(structure, data_delete) averageTimeDelete += deleteTime BenchRes = append(BenchRes, csvwriter.BenchmarkResult{ Structure: nameStruct, Mode: mode, Operation: "Удаление", Time: deleteTime, }) fmt.Printf("%s | Вставка | %s | Время: %f\n", nameStruct, mode, insertTime) fmt.Printf("%s | Поиск | %s | Время: %f\n", nameStruct, mode, searchTime) fmt.Printf("%s | Удаление | %s | Время: %.9f\n", nameStruct, mode, deleteTime) } averageTimeInsert /= countRepeat averageTimeSearch /= countRepeat averageTimeDelete /= countRepeat BenchRes = append(BenchRes, csvwriter.BenchmarkResult{ Structure: nameStruct, Mode: mode, Operation: "Вставка (среднее)", Time: averageTimeInsert, }) BenchRes = append(BenchRes, csvwriter.BenchmarkResult{ Structure: nameStruct, Mode: mode, Operation: "Поиск (среднее)", Time: averageTimeSearch, }) BenchRes = append(BenchRes, csvwriter.BenchmarkResult{ Structure: nameStruct, Mode: mode, Operation: "Удаление (среднее)", Time: averageTimeDelete, }) fmt.Printf("%s | Вставка | %s | Время (среднее): %f\n", nameStruct, mode, averageTimeInsert) fmt.Printf("%s | Поиск | %s | Время (среднее): %f\n", nameStruct, mode, averageTimeSearch) fmt.Printf("%s | Удаление | %s | Время (среднее): %f\n", nameStruct, mode, averageTimeDelete) csvwriter.AppendRaw(BenchRes) } func isSorted(data []ds.MyData) bool { for i := 0; i < len(data)-1; i++ { if data[i].Name > data[i+1].Name { return false } } return true } func Test(nameStruct string, factory StructureFactory) { data := GenerateTestData() // fmt.Println("items", isSorted(data.Items)) // fmt.Println("items sort", isSorted(data.ItemsSorted)) testForData(nameStruct, "Случайный", factory, data.Items, data.Search, data.ToDelete) testForData(nameStruct, "Отсортированный", factory, data.ItemsSorted, data.Search, data.ToDelete) } func main() { csvwriter.CreateEmptyCSV("results", "benchmarks.csv") fmt.Println("============= Начало тестов =============") Test("Связный список", NewLinkedList) Test("Хеш таблица", NewHashTable) Test("Бинарное дерево поиска", NewBinSearchTree) // fmt.Println("User_0001" < "User_00100") // fmt.Println(isSorted(dg.RecordsShuffled(10000))) }