Який найбільш просторовий спосіб реалізації структури даних графіків?


14

Я, як правило, реалізую графіки як подвійно пов'язані списки, але це мій досвід досить неефективно, оскільки мені потрібні k покажчики / посилання на k сусідів, тому для непрямої графіки я мав би ~ 2k сусідніх посилань у списках, якщо моя математика правильна. Чи є кращий спосіб економії місця? Я знаю, що деякі з посилань можуть бути єдиними, якщо графік спрямований, але чи є спосіб зробити цю роботу кращою?

Відповіді:


12

Добре, якщо про ефективність простору все, що вам важливо, тоді найкраще буде стисла структура даних - але, звичайно, це не дуже ефективно для доступу чи оновлення .....

Якщо ваш графік має відносно невелику кількість вузлів і досить щільний (скажімо, щонайменше 5% усіх можливих з'єднань), то, можливо, ви можете вважати, що для створення матриці суміжності більш просторовим є використання, ніж використання крайових списків. Для цього знадобиться лише один біт на можливе (спрямоване) з'єднання, і n * n біт усього, де у вас n вузлів.

В іншому випадку, якщо вам потрібно використовувати сусідні посилання, то ви не можете легко зробити краще, ніж одне посилання на посилання, оскільки це мінімальний інформаційний вміст, який потрібно зберігати. Якщо ви хочете зворотних посилань, вам знадобиться вдвічі більше посилань.

Є кілька хитрощів, які ви можете спробувати на цьому. Наприклад, ви можете спробувати поділитися підмножинами посилань (якщо A і B посилаються на кожен з C, D, E, тоді зберігайте лише список посилань C, D, E .....). Однак це складеться досить швидко, і я сумніваюся, що варто докласти зусиль у більшості випадків.

Ще один трюк - якщо припустити, що ваш графік має достатню кількість вузлів, ви, безумовно, заощадите простір шляхом індексації - наприклад, використовуючи 16-бітний номер індексу вузла, а не повний покажчик / посилання.


Якщо всі посилання не спрямовані, можна заощадити половину місця, зберігаючи лише край від низького до високого вузла.
Дедуплікатор

6

Це буде залежати від структури ваших даних.

Для щільного графіка з непрямими краями ви не можете перемогти список бітових масивів, що представляють трикутну матрицю. А List<BitArray>наприклад. Логічно це виглядатиме так:

 0123
0
11
211
3001
41010

Звідти ви можете використовувати індекс кореневого BitArray для індексації до списку, в якому зберігаються дані вашого вузла.

Наприклад, отримання всіх сусідів вузла буде таким:

// C#
List<Node> Nodes = /* populated elsewhere */
List<BitArray> bits = /* populated elsewhere */
public static IEnumerable<Node> GetNeighbours(int x)    
{
    for (int i = 0; i < bits[idx].Count; i++)
    {
        if (this.bits[idx][i])
            yield return this.Nodes[i];
    }

    for (int i = 0; i < this.Nodes.Count; i++)
    {
        if (idx < this.bits[i].Count && this.bits[i][idx])
            yield return this.Nodes[i];
    }    
}

(зауважте, що ви також можете вибрати тип індексу, залежно від обсягу даних, бути байтом чи ушортом або щось у цьому рядку, оскільки всі індекси будуть позитивними. Я не вважаю це мікрооптимізацією, оскільки це тривіально)

Для спрямованого графа ви б пройшли маршрут масиву * n бітів, щоб зберегти зв’язок ... якщо тільки це не дуже рідко порівняно з кількістю вузлів, де ви можете перейти до списку суміжних індексів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.