以下を参考にしています。
Data-Structures-using-Python/Linked Lists/DoublyLinkedList.py
双方向リスト
片方向リストは後方向へのリンクだけでしたが、双方向リスト(Doubly-Linked List)は、前方向、後方向、双方へのリンクを持っています。
メリット
- 前のノードのアドレス情報なしでノードの削除が行える。
デメリット
- 片方向リストと比較するとポインタが増えてしまうので、容量が増える。
- リストの操作の際に、ポインタの操作が増えるので、時間がかかる。
双方向リスト(doubly-linked list)は、より洗練された連結リスト。各ノードには2つのリンクがあり、1つが次のノード(前方リンク)、もう1つが後ろのノード(後方リンク)を指す。リストの先頭のノードには後ろのノードがないので、後方リンクにはヌル値を格納するか、空のリストを指す。リストの最後尾のノードには次のノードがないので、前方リンクにはヌル値を格納するか、空のリストを指す。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
class Node(): # ノードは前方向、後方向へのリンクを持つ。 def __init__(self, data, next = None, previous = None): self.data = data self.next = next self.previous = previous # データを設定する。 def set_data(self, data): self.data = data # データを取得する。 def get_data(self): return self.data # 次のノードを設定する。 def set_next(self, next): self.next = next # 次のノードを取得する。 def get_next(self): return self.next # 前のノードを設定する。 def set_previous(self, previous): self.previous = previous # 前のノードを取得する。 def get_previous(self): return self.previous
class DoublyLinkedList(): def __init__(self): self.head = None self.tail = None
双方向リストのデータ参照
データの出力
片方向リストと変わりません。
- ノードの持つリンクを辿る。
- 参照したノードのデータを表示する。
- 次のリンクがNullであれば終了する。
# データの出力 def print_doubly_linked_list(self): temp = self.head while(temp is not None): print(temp.data, end=' ') temp = temp.get_next()
双方向リストのデータ挿入
先頭に挿入
- 新しいノードの右のポインタを現在の先頭のノードを指すように、左のポインタはNullに設定する。
# 先頭に挿入する def insert_at_start(self, data): new_node = Node(data) if self.head is None: self.head = new_node self.tail = new_node else: new_node.set_previous(None) new_node.set_next(self.head) self.head.set_previous(new_node) self.head = new_node
最後に挿入
- 新しいノードの右のポインタをNullに、左のポインタを現在の最後のノードを指すようにする。
# 最後に挿入する def insert_at_end(self, data): if self.head is None: self.head = Node(data) self.tail = self.head else: temp = self.head while temp.get_next() is not None: temp = temp.get_next() temp.set_next(Node(data, None, temp)) self.tail = temp.get_next()
間に挿入
- 挿入する位置まで移動する。
- 新しいノードの右のポインタを挿入箇所のノードの次のノードに、左のポインタを挿入箇所のノードにする。
- 挿入箇所のノードの右のポインタを新しいノードに、挿入箇所ノードの次ノードの左のポインタを新しいノードに設定する。
# ある場所のノードを取得する。 def get_node(self, position): temp = self.head if temp is None: return None i = 0 while i < position and temp.get_next() is not None: temp = temp.get_next() if temp is None: break i += 1 return temp # 間にノードを挿入する。 def insert_position(self, position, data): temp = self.head if self.head is None or position == 0: self.insert_at_start(data) elif position > 0: temp = self.get_node(position) if temp is None or temp.get_next() is None: self.insert_at_end(data) else: new_node = Node(data) new_node.set_next(temp.get_next()) new_node.set_previous(temp) temp.get_next().set_previous(new_node) temp.set_next(new_node)
双方向リストのデータ削除
先頭を削除
def delete(self, data): temp = self.head if temp.get_next() is not None: # 先頭を削除する if temp.data == data: temp.get_next().set_previous(None) self.head = temp.get_next() temp.set_next(None) return else: while temp.get_next() is not None: if temp.get_data() == data: break temp = temp.get_next() if temp.next: # 間の要素を削除する temp.previous.next = temp.next temp.next.previous = temp.previous temp.next = None temp.previous = None else: # 最後を削除する temp.previous.next = None temp.previous = None return if temp is None: return
双方向リストのコード
class Node(): # ノードは前方向、後方向へのリンクを持つ。 def __init__(self, data, next = None, previous = None): self.data = data self.next = next self.previous = previous # データを設定する。 def set_data(self, data): self.data = data # データを取得する。 def get_data(self): return self.data # 次のノードを設定する。 def set_next(self, next): self.next = next # 次のノードを取得する。 def get_next(self): return self.next # 前のノードを設定する。 def set_previous(self, previous): self.previous = previous # 前のノードを取得する。 def get_previous(self): return self.previous class DoublyLinkedList(): def __init__(self): self.head = None self.tail = None # データの出力 def print_doubly_linked_list(self): temp = self.head while(temp is not None): print(temp.data, end=' ') temp = temp.get_next() # 先頭に挿入する def insert_at_start(self, data): new_node = Node(data) if self.head is None: self.head = new_node self.tail = new_node else: new_node.set_previous(None) new_node.set_next(self.head) self.head.set_previous(new_node) self.head = new_node # 最後に挿入する def insert_at_end(self, data): if self.head is None: self.head = Node(data) self.tail = self.head else: temp = self.head while temp.get_next() is not None: temp = temp.get_next() temp.set_next(Node(data, None, temp)) self.tail = temp.get_next() # ある場所のノードを取得する。 def get_node(self, position): temp = self.head if temp is None: return None i = 0 while i < position and temp.get_next() is not None: temp = temp.get_next() if temp is None: break i += 1 return temp # 間にノードを挿入する。 def insert_position(self, position, data): temp = self.head if self.head is None or position == 0: self.insert_at_start(data) elif position > 0: temp = self.get_node(position) if temp is None or temp.get_next() is None: self.insert_at_end(data) else: new_node = Node(data) new_node.set_next(temp.get_next()) new_node.set_previous(temp) temp.get_next().set_previous(new_node) temp.set_next(new_node) def delete(self, data): temp = self.head if temp.get_next() is not None: # 先頭を削除する if temp.data == data: temp.get_next().set_previous(None) self.head = temp.get_next() temp.set_next(None) return else: while temp.get_next() is not None: if temp.get_data() == data: break temp = temp.get_next() if temp.next: # 間の要素を削除する temp.previous.next = temp.next temp.next.previous = temp.previous temp.next = None temp.previous = None else: # 最後を削除する temp.previous.next = None temp.previous = None return if temp is None: return if __name__ == '__main__': doubly_linked_list = DoublyLinkedList() doubly_linked_list.insert_at_start(1) doubly_linked_list.insert_at_start(2) doubly_linked_list.insert_at_end(3) doubly_linked_list.insert_at_start(4) doubly_linked_list.print_doubly_linked_list() print() print(doubly_linked_list.get_node(3).get_data()) doubly_linked_list.insert_position(3, 5) doubly_linked_list.print_doubly_linked_list() print() doubly_linked_list.delete(2) doubly_linked_list.print_doubly_linked_list()