(この本をお勧めします初心者「西のデータ構造」データ構造から概要)
ディレクトリ
静的リスト
以下のリストで静的配列リストと呼ばれます。
二つのドメイン、データ、およびCURによってアレイのデータ要素を聞かせて、データは、配列インデックスの後続の要素に格納されたポインタのCURアナログリンクされたリストを格納します。
#define MAXSIZE 1000;
typedef int ElemType;
typedef int Status;
typedef struct
{
ElemType data;
int cur;
}Component,StaticLinkList[MAXSIZE];
また、他の魔法の効果の配列の最初と最後の要素は、私たちの特別な要素である、データが存在しません。
(バックアップチェーン:配列が連続している、一般的には、確かに使用していないがあるでしょうリンクリスト、場合、我々は、配列要素が待機リストとして知られていない使用します。)
図は、何が良いのこの定義は、それですか?だから我々は、ヘッドノードの位置を知っていることを、リストが(後で容易にするために、最初のバックアップノードチェーンの位置を知っても、どこ初め(図0ならば、それはリストが空であることを意味します)を知っているだろう挿入)
//初始化数组
//space[0].cur为头指针, “0”表示空指针
Status InitList(StaticLinkList space)
{
int i;
for(i=0;i<MAXSIZE-1;i++)
{
space[i].cur=i+!;
}
space[MAXSIZE-1].cur=0;
return OK;
}
挿入の静的リスト
リスト挿入ノードの削除は、それぞれのmalloc()及び遊離()関数は、2つです。我々は挿入および削除この2つの機能を操作することができますを実装する必要がありますので、しかし配列で、問題のあるアプリケーションとリリースノードは、存在しません。
アイデアの挿入:我々は最初のストレージノードのバックアップチェーンの位置のインデックス0の配列要素を知っている、そしてそれは我々が挿入部位を望むものです。
int Malloc_SLL(StaticLinkList space)
{
int i=space[0].cur; //我们想要存的位置,即第一个备用空闲的下标
if(space[0].cur)
space[0].cur=space[i].cur; //插入后第一个备用空闲没有了,转到它的cur去
return i; //返回分配的结点下标
}
だから我々は問題リンクリストデータを解決し、その後、我々は次号でリストがある解決しなければなりません。
//在L中第i个元素之前插入新的数据元素e
Status ListInsert(StaticLinkList L,int i,ElemType e)
{
int j,k,l;
k=MAX_SIZE-1; //k是最后一个元素的下标 它的cur是第一个非空下标
if( i<1 || i>ListLength(L)+1 )
return ERROR;
j=Malloc_SSL(L); //j是空闲分量的下标
if( j )
{
L(j).data=e;
for(l=1;l<=i-1;l++) //找到第i个元素之前的位置
k=L[k].cur;
L(j).cur=L[k].cur;
L[k].cur=j;
return OK;
}
return ERROR;
}
図の例では、即ち、静的リスト挿入動作を実現します。
削除の静的リスト
削除や、所有する必要の操作を挿入無料()関数を達成するために
//删除在L中的第i个数据元素e
Status ListDelete(StaticLinkList L,int i)
{
int j,k;
k=MAX_SIZE-1; //k是最后一个元素的下标 它的cur是第一个非空下标
if( i<1 || i>ListLength(L)+1 )
return ERROR;
j=Malloc_SSL(L); //j是空闲分量的下标
for(l=1;l<=i-1;l++) //找到第i个元素之前的位置
k=L[k].cur;
j=L[k].cur;
L[k].cur=L[j].cur;
Free_SSL(L,j);
return OK;
}
void Free_SSL(StaticLinkList space, int k)
{
space[k].cur=space[0].cur;
space[0].cur=k;
}
int ListLength(StaticLinkList L)
{
int j=0;
int i=L[MAXSIZE-1].cur;
while(i)
{
i=L[i].cur;
j++;
}
turn j;
}
循環リスト
円形のリンクリストは、定義により、単一リンクリストポインタ末端ノードへの最初のノードを指すヌル・ポインタであり、それは尾のリング、ヘッドを形成する全体単鎖を引き起こします。
円形リスト内の単一のリンク・リストメイン差嘘ループの決意条件単一のリストには、決定されたP->次の空かどうかであり、周期が決定リストであるP->次は、ヘッドノードと同じです。
循環リスト、それは何を使用ですか?
ビット循環リストは、環状構造的特徴を、データを処理するための、適切なチェーンリンクの頭に尾部から、より便利です
単一リンクリストでは、我々は最初のノードと最後のノードにアクセスしたい場合、彼らはO(1)とO(n)の時間を必要としています。循環リストに、我々は、ヘッドポインタをキャンセルした場合、尾部へのポインタ、示されるように、その後、平均のみをO(1)時間と最後のノードへの最初のアクセスノード。
テールポインタそれは何を使用ですか?
テールポインタは非常に便利であるときに、2つの組み合わせ循環リストは、リンクされたリストです。
二重リンクリスト
二重連結リスト内の各ノードのための単独でリンクされたリストであり、その前駆ノードドメインへのポインタを設定します。
(オタク時からのデータ構造とアルゴリズムの米国の列の図)
typedef struct DulNode
{
ElemTyoe data;
struct DuLNode *prior; //直接前驱指针
struct DuLNode *next; //直接后继指针
}DulNode,*DuLinkList;
二重、特に使用は、それは何も多いので、多くのスペースのある、ストレージのと同じ量の一本鎖に比べてリンクリスト?
まずプット結論:二重にリンクされたリストのためには、できる前駆体ノードノード便利見つけることが、そうではいくつかのケース、効率的で、単独のリストを連結した場合に比べて挿入し、削除する方が簡単です
冗談で、インサートと時間の複雑さの点では削除単一リンクリストは、すでにO(1)であり、またどのように最適化するには、少しいじめっ子私は今それを読んで!
まあ、私は2つの密接にリンクされたリストの操作について話しましょう:
1、削除
穏やかな穏やかでは、我々はO(1)は非常に片側ていると言う、単純にこの操作の削除を意味しますが、削除する前に、我々は、削除したい場所を見つけるために横断する必要があり、この場所は、大きな消費している、時間の複雑さに対応するありますO(n)は、この場所で二重にリンクされたリストの最適化の低下です。
両方の場合において、リンクされたリストから外側⽆ほぼ⼀データを削除:ノード削除ノード「の値を所定の値に等しい」、所与のノードのポインタを削除します。
それはかつての単鎖または双方向リンクリストであるかどうか、慣行が同じであることは、削除操作で指定された値が見つかるまで、1は、スクラッチトラバースノードからノードを起動する必要があり、すべての操作が同じで、それは言う必要はありませんでした。
後者の場合で見てみましょう:指定されたノードのポインタを削除します。その横に指し示すポインタを変更する変更するには、ヘルプにこのノード前駆体ノードを持つように、このノードのニーズを削除しますが、私は後続ノード単独リンクリストのシンプルな、本当にMozheの先行ノードを見つけ、唯一のトラバースにゼロからスタートすることができ、それはまだにあり再びO(n)の時間計算量でトラバーサル、。この時点でアウトニヤリ二重リンクリスト、指を動かし、まあ、これは前駆ノードそれはありませんが、それでも、あまりにも多くのトラブルを通過する必要があります。この場合、二重リンクリストは、単一〜と比較して、削除操作、二重にリンクされたリストを見つける、または優位降下を有することのみO(1)時間複雑さの先行ノードを必要とします
そして、循環リスト二重にリンクされたリストの話、私たちは自然にスーパー上司と考えることができます:双方向循環リスト、次のように、私はそれについて話すことはありません