Оптимизация. Списки и последовательный доступ


Список как структура для хранения данных известна достаточно широко. Фактически, наверняка в любом курсе программирования ее изучают в том или ином виде.

Но то, что обычно усваивает студент (читать: "будущий программист") заключается примерно в следующем:
Списки организуются на динамической памяти. Динамическая память, по мнению студента, это то, что можно получить при помощи операторов new и удалить dispose.

Списки организуются при помощи одного указателя на голову списка и, включенных в каждый элемент, указателей на следующий элемент списка. Точнее, может присутствовать указатель и на предыдущий элемент, а также указатель на хвост списка, это не суть важно.

Кроме этого, средний студент часто путает список с очередью: все дело в том, что обычно на лабораторных работах дается задание реализовать очередь, выбрав для ее внутреннего устройства список. На самом деле, очередь это "нечто", что позволяет поместить туда элемент и получить его согласно правилу FIFO ("First In, First Out" --- "Первый вошел, первый вышел"). 

Тем не менее, я не хотел обижать студентов, совсем нет. Просто очень часто, если практически не постоянно можно увидеть один и тот же подход: организацию списков при помощи указателей. Проблема заключается в том, что такая реализация списков не единственна и достаточно часто не эффективна. 

Допустим, программист реализует некую структуру данных, основываясь на хеш-таблице, при этом коллизии решаются списками элементов. Что может сделать программист, имеющий стереотипы наподобие предыдущих? Что-нибудь в духе:
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
 
struct hash_list
{
int key;
hash_list* next;
};
 
#define HASH_TABLE_SIZE 511
 
hash_list* hash[HASH_TABLE_SIZE];
 
#define COUNT 1000000
 
struct {
unsigned int iterations;
} stat;
 
int main()
{
unsigned int i, j;
 
int k;
hash_list* ptr, *prev_ptr;
 
bzero((char*)hash, sizeof(hash));
bzero((char*)&stat, sizeof(stat));
 
srandom(time(NULL));
 
for(i = 0; i < COUNT; i++)
{
 
k = random() & 8191;
 
prev_ptr = NULL;
for(ptr = hash[k%HASH_TABLE_SIZE];
ptr && ptr->key != k;
prev_ptr = ptr, ptr = ptr->next, stat.iterations++)
;
 
if(!ptr)
{
if(prev_ptr)
{
prev_ptr->next = (hash_list*)calloc(1, sizeof(hash_list));
prev_ptr->next->key = k;
}
else
{
hash[k%HASH_TABLE_SIZE] = (hash_list*)calloc(1, sizeof(hash_list));
hash[k%HASH_TABLE_SIZE]->key = k;
}
}
}
 
printf("Iterations: %u\n", stat.iterations);
}


 
« Предыдущая статья   Следующая статья »