リンクリストの目的の1つは、わずかなコストでノードを簡単に追加および削除できるようにすることです。
その機能を放棄してペイロードポインタの配列を使用することはできますが、リンクリストではなくなります(同じノードを算術増分で簡単に取得できる場合、次のノードへのポインタを使用する目的は何ですか?)。
例:
struct
{
struct node *next;
void *payload;
...
} node;
node *root = NULL;
ノードにスペースを割り当てない場合は、
typedef struct
{
void *payload;
...
} node;
node *vector = NULL;
size_t vectorsize = 0;
そして、最初に必要な数のノードにスペースを割り当て、realloc
必要に応じてリストを拡張するために使用しmemmove
、削除されたノードを超えてノードをシフトバックすることによってノードを削除します。これにより、ノードを追加または削除するときに明らかにパフォーマンスが低下します。一方、n番目のノードはちょうどvector[n]
です。
繰り返しますが、これはもはやリンクリストではありません。これが必要な場合は、リンクリストではなくポインタの配列を使用する方が適切な場合があります。
それは私に思い出させます、あなたはあなたが直接アドレス指定能力を必要とする理由を説明するのが良いでしょう(「問題を述べてください、解決策を実装する方法を尋ねないでください」):それはあなたが必要とするのは配列でもないかもしれませんリンクリストでもありませんが、誰が知っているのでしょうか?おそらく、リングバッファ、スタック、丘、または二分木です。
一部の実装では、 2つの結合構造を展開することもできます。たとえば、特に最近挿入されたデータの多くの挿入と削除を伴う最初のフェーズで(二重に?)リンクリストを使用する場合があります。次に、ノード番号によって駆動される直接アドレス指定が必要な第2フェーズのポインター配列を作成して切り替えます(配列をリストノードアドレスの「キャッシュ」として使用します)。
for (listsize = 0, scan = root; scan; scan = scan->next)
listsize++;
if (NULL == (vector = (node *)malloc(listsize * sizeof(node))))
{
// out of memory
return EXIT_FAILURE;
}
for (listsize = 0, scan = root; scan; scan = scan->next)
vector[listsize++] = scan;
// Now vector[i]->payload is the payload of the i-th node