序文
最近、Wangdao大学院入試のデータ構造に関する本を書いていましたが、リンクリストを確認し、いくつかの練習問題を書いたところ、リンクリストから最小値ノードを見つける方法が2つあることがわかりました。単一リンクリストまたは循環単一リンクリストは、サイクルの単なる変更条件です。
同様に、「リンクリストの最小値を順番に見つけて、印刷して削除し、スペースを解放する」という問題も同じであると結論付けることができますが、内側と外側のループの条件を変更することができます。
したがって、結論を出す必要があると感じています。
1.トピックの要約1(1レベルのループ)
- ヘッドノードを持つ単一リンクリストLの最小ノードを削除するための効率的なアルゴリズムを書いてみてください(最小ノードが一意であると仮定)
- ヘッドノードを持つ単一の循環リンクリストL内の最小ノードを削除するための効率的なアルゴリズムを作成してみてください(最小ノードが一意であると想定)
上記の2つのトピックは、単一リンクリストのタイプのみが異なり、他のトピックは同じです。タイトルからわかるように、最小値を見つける必要があるのは1回だけなので、whileループのレイヤーで十分です。
方法1
(例として、通常の単一リンクリストを取り上げます)
アルゴリズムのアイデア:pを使用して単一リンクリストを最初から最後までスキャンし、preがpノードの先行を指し、minpを使用して最小値(最初はp)でノードポインターを保存し、minpreがの先行を指します。 minpノード(最初はpre)。スキャン中に比較し、p->dataがminp->dataより小さい場合は、pとpreをそれぞれminpとminpreに割り当てます。pがスキャンされると、minpは最小値ノードを指し、minpreは最小値ノードの先行ノードを指し、次にminpが指すノードを削除します。
コードは次のように表示されます。
LinkList Delete_min(LinkList &L){
// L是带头结点的单链表
LNode *pre = L,*p = pre->next;// p为工作指针,pre指向其前驱
LNode *minpre = pre,*minp = minpre->next; // 保存最小值结点以及其前驱
while(p!=NULL){
if(p->data<minp->data){
minp = p; //找到比之前找到的最小值结点更小的结点
minpre = pre;
}
pre = p; // 继续扫描下一个结点
p = p->next;
}
minpre->next = minp->next;// 删除最小值结点
free(minp);
return L;
}
では、単一リンクリストが循環単一リンクリストに置き換えられた場合はどうなるでしょうか。
実際、単一リンクリストと循環単一リンクリストの違いは、単一リンクリストの最後のノードの次がNULLを指しているのに対し、循環単一リンクリストの最後のノードの次はヘッドノードL。
したがって、ループ条件のみを変更する必要があり、その他は変更されません。
方法2
アルゴリズムのアイデア:set * p、* pre、pは後方に移動し続けます。preはpの先行であり、最小ノードの先行を記憶するために使用されます。各比較は、p->nextとpre->nextの比較です。p->nextがpre->nextより小さい場合、pre = p(最小ノードが見つかった場合、preはその先行ノードです)。
コードは次のように表示されます。
LinkList Delete_min(LinkList &L){
// L是带头结点的单链表
LNode *pre = L,*p = pre->next;// p为工作指针,pre指向其前驱
LNode *u;
while(p->next!=NULL){
// 注意这里的条件变成了 p->next!=NULL
if(p->next->data<pre->next->data){
pre = p; // 记住当前最小值的前驱 (p->next是最小值结点)
}
p = p->next;
}
u = pre->next;// 这是最小值结点
pre->next = u->next;// 删除最小值结点
free(u);// 释放空间
return L;
}
循環単一リンクリストに切り替えるには、ループ条件を変更するだけで済みます。(単一リンクリストの最後のノードの次はNULLを指し、循環単一リンクリストの最後のノードの次はヘッドノードLを指します。)
2.トピックサマリーII(2層サイクル)
- ヘッドノードを持つ単一リンクリストが与えられた場合、ヘッドをヘッドポインター、ノード構造は(data、next)、データは整数要素、nextはポインター、アルゴリズムを記述してみてください。各ノードを単一で出力します。リンクリストを昇順で表示し、ノードが占有していたストレージスペースを解放します(補助スペースとしてのアレイの使用は許可されていません)
- ノードがすべて正の整数であるヘッドノードを持つ単一循環リンクリストがあります。テーブル内でノード値が最小のノードを繰り返し検索して出力し、単一リンクリストが空になるまでノードを削除してから、ヘッダーノードを削除するアルゴリズムを設計します。
上記の2つの質問の核心は、実際には次のとおりです。
反复找出表中结点值最小的节点并输出
前の質問1と2は、1回だけ見つける必要があります。実際、よく考えて繰り返し見つけるには、2層の循環が必要です。
そして、内側のループはトピックサマリー1のコードだけではありませんか?内側のループはリンクリストをトラバースして最小値を見つけるためですが、拡張と拡張の問題では、最小値が見つかって削除されるたびに、リンクリストが変更され、次に最小値が見つかって再び削除されます、そしてそれは再び変化するので、以下を制御するために外部ループが必要です:直到链表为空时,才不会对链表进行遍历
方法1
void Delete_min(LinkList &L){
// L是带头结点的单链表
LNode *p,*pre,*minp,*minpre;
while(L->next!=NULL){
p = L->next; pre = L;
minp = p; minpre = pre;
while(p!=NULL){
if(p->data<minp->data){
minp = p; //找到比之前找到的最小值结点更小的结点
minpre = pre;
}
pre = p; // 继续扫描下一个结点
p = p->next;
}
print(minp->data)// 输出最小值结点元素
minpre->next = minp->next;// 删除最小值结点
free(minp);
}
free(L);
}
訂正:下の図では、関数の戻り値は無効です。
方法2
同様に、Lをヘッドに置き換えるだけです。
void Delete_min(LinkList &head){
// L是带头结点的单链表
LNode *pre,*p ,*u;
while(head->next!=NULL){
pre = head;
p = pre->next;
while(p->next!=NULL){
// 注意这里的条件变成了 p->next!=NULL
if(p->next->data<pre->next->data){
pre = p; // 记住当前最小值的前驱 (p->next是最小值结点)
}
p = p->next;
}
print(pre->next->data);// 输出最小值结点的数据
u = pre->next;// 这是最小值结点
pre->next = u->next;// 删除最小值结点
free(u);// 释放空间
}
free(head);
}