連結リストの基本操作:要素削除、カスタム設計、反転処理

連結リストの要素削除

例:入力:head = [1,2,6,3,4,5,6], val = 6 出力:[1,2,3,4,5]

連結リストの設計

連結リストクラスで以下の機能を実装します:

get(index):連結リストのindex番目のノードの値を取得します。インデックスが無効な場合は-1を返します。
addAtHead(val):連結リストの最初の要素の前に値がvalのノードを追加します。挿入後、新しいノードが連結リストの最初のノードになります。
addAtTail(val):値がvalのノードを連結リストの最後の要素に追加します。addAtIndex(index,val):連結リストのindex番目のノードの前に値がvalのノードを追加します。indexが連結リストの長さに等しい場合、ノードは連結リストの末尾に追加されます。indexが連結リストの長さより大きい場合は、ノードは挿入されません。indexが0より小さい場合は、先頭にノードを挿入します。deleteAtIndex(index):インデックスindexが有効な場合、連結リストのindex番目のノードを削除します。

連結リストの反転

例:入力: 1->2->3->4->5->NULL 出力: 5->4->3->2->1->NULL

まず連結リストクラスを定義します

class リストノード():
    def __init__(self,値=0,次=None):
        self.値 = 値
        self.次 = 次

考え方:1.n番目のノードの値を取得:nの値に到達するためにどうループすればよいか、いつループを停止するか、インデックスが有効な場合、毎回現在のポインタを1つ後ろに移動します

考え方:2.solutionクラス内に配列から連結リストを作成するメソッドを定義し、さらに連結リストを出力するメソッドを定義すれば、入出力がより簡潔になります

class 解決策:

    ## 連結リストを設計する過程で、データ領域とポインタ領域に加えて、連結リストのサイズという属性も必要です
    def __init__(self):
        self.ダミーノード = リストノード() # すべてのメソッドのために仮想頭ノードを構築
        self.サイズ = 0

    ## リストから連結リストを作成し、連結リストのサイズを取得
    def 連結リスト作成(self,配列:リスト[int])->リストノード:
        ヘッド = リストノード(値=配列[0])
        self.ダミーノード.次 = ヘッド
        self.サイズ = 1
        現在 = ヘッド
        for i in range(1,len(配列)):
            現在.次 = リストノード(値=配列[i])
            現在 = 現在.次
            self.サイズ += 1
        return ヘッド

    def ノード出力(self,ヘッド):
        if ヘッド is None:
            return
        現在 = ヘッド
        while 現在:
            print(現在.値, end="->")
            現在 = 現在.次
        print('null')

1. 連結リストの要素削除

def 要素削除(self, ヘッド:オプション[リストノード], 値: int) -> オプション[リストノード]:
    # 削除プロセスを簡化するために仮想頭ノードを作成
    ダミーヘッド = リストノード(次=ヘッド)
    
    # リストを走査して値がvalのノードを削除
    現在 = ダミーヘッド
    while 現在.次:
        if 現在.次.値 == 値:
            現在.次 = 現在.次.次
        else:
            現在 = 現在.次
    
    return ダミーヘッド.次

2. インデックスがindexのノードの値を取得

def 値取得(self, ヘッド:オプション[リストノード], 目標:int)->int:
    現在 = ヘッド # ポインタを頭ノードから開始
    # 現在のノードが最後のノードではない、リストが空ではない
    if 目標 < 0 or 目標 > self.サイズ:
        return -1
    else:
        while(目標-1):
            現在 = 現在.次
            目標 -= 1
        return 現在.値

3. 先頭ノードに挿入

def 先頭挿入(self, ヘッド:オプション[リストノード], 値:int)->リストノード:
    現在 = self.ダミーノード # ポインタを仮想頭ノードから開始
    新ノード = リストノード(値=値, 次=ヘッド)
    現在.次 = 新ノード
    self.サイズ += 1
    return 現在.次

4. 末尾ノードに挿入

def 末尾挿入(self, ヘッド:オプション[リストノード], 値:int)->リストノード:
    現在 = self.ダミーノード
    while(現在.次):
        現在 = 現在.次
    
    現在.次 = リストノード(値=値, 次=現在.次)
    self.サイズ += 1
    return ヘッド

5. インデックスindexに挿入

def 挿入(self, ヘッド:オプション[リストノード], 位置:int, 値:int)->リストノード:
    現在 = self.ダミーノード # 0番目のノードと見なす
    if 位置 < 0:
        self.先頭挿入(ヘッド, 値)
    elif 位置 > self.サイズ:
        self.末尾挿入(ヘッド, 値)
    else:
        while(位置-1):
            現在 = 現在.次
            位置 -= 1
        
        新ノード = リストノード(値=値, 次=現在.次)
        現在.次 = 新ノード
        self.サイズ += 1
        return ヘッド

6. インデックス位置のノードを削除

def 削除(self, ヘッド:オプション[リストノード], 位置:int)->リストノード:
    現在 = self.ダミーノード # 0番目のノードと見なす
    if 位置 < 0 or 位置 >= self.サイズ:
        return ヘッド
    
    # 削除位置の直前のノードまで移動
    for _ in range(位置):
        現在 = 現在.次
    
    # ノードを削除
    削除ノード = 現在.次
    現在.次 = 削除ノード.次
    self.サイズ -= 1
    return ヘッド

7. 連結リストの反転

# 連結リストを反転するメソッド
def 反転(self, ヘッド:オプション[リストノード])->オプション[リストノード]:
    # 反転:現在ノードの次のノードの次を現在ノードに指させる
    前 = None
    現在 = ヘッド
    # 次のnextを変更すると、元のノード間のリンクが切断されるため、事前に次のノードを保存する必要がある
    while (現在):
        一時 = 現在.次
        現在.次 = 前
        前 = 現在
        現在 = 一時
    return 前

関数呼び出しの例

if __name__ == "__main__":
    配列 = [3,3,1,2,5,3,5,6,3,3,7,3]
    位置 = 4  # 挿入位置
    値 = 3   # 挿入値
    s = 解決策()
    l = s.連結リスト作成(配列)
    # 作成した連結リスト
    s.ノード出力(l)
    
    # 値の取得
    # 取得値 = s.値取得(l, 位置)
    # print(取得値)
    
    # 先頭への挿入
    # l1 = s.先頭挿入(l, 値)
    
    # 末尾への挿入
    # l2 = s.末尾挿入(l, 値)
    
    # 指定位置への挿入
    # l3 = s.挿入(l, 位置, 値)
    
    # 連結リストの反転
    l4 = s.反転(l)
    
    # s.ノード出力(l1)
    # s.ノード出力(l2)
    # s.ノード出力(l3)
    s.ノード出力(l4)

タグ: Python 連結リスト データ構造 アルゴリズム

7月12日 18:07 投稿