Pythonで連結リストが降順にソートされているか判定する方法(反復処理・再帰の両方を解説)
問題の概要
連結リスト(リンクリスト)が与えられたとき、それが降順(非増加順)にソートされているかどうかを判定する2つの関数を定義することを考えます。1つ目の関数は反復処理で動作し、2つ目の関数は再帰呼び出しで動作します。
たとえば、入力が L = [15, 13, 8, 6, 4, 2] の場合、すべての要素が降順に並んでいるため、出力は True となります。
解決のためのアプローチ
この問題は、次の手順で解くことができます。
- 反復版の関数 solve_iter() を定義します(引数として先頭ノード head を受け取ります)。
・head が null(None)の場合はTrueを返します。
・head の次ノードが存在する間、以下を繰り返します。
- current := head とします。
- current の値が current の次ノードの値以下であればFalseを返します。
- head := 次ノード として進めます。
・ループが完了したらTrueを返します。 - 再帰版の関数 solve_rec() を定義します(同様に head を受け取ります)。
・head が null、または head の次ノードが null の場合はTrueを返します(リスト末尾まで確認できたことを意味します)。
・「head の値が次ノードの値より大きい」かつ「solve_rec(head の次ノード) がTrue」のときにTrueを返し、それ以外はFalseを返します。
実装例
理解を深めるために、以下のPythonコードをご覧ください。
class ListNode:
def __init__(self, data, next=None):
self.val = data
self.next = next
def make_list(elements):
head = ListNode(elements[0])
for element in elements[1:]:
ptr = head
while ptr.next:
ptr = ptr.next
ptr.next = ListNode(element)
return head
def solve_iter(head):
if head == None:
return True
while head.next != None:
current = head
if current.val <= current.next.val:
return False
head = head.next
return True
def solve_rec(head):
if head == None or head.next == None:
return True
return head.val > head.next.val and solve_rec(head.next)
L = make_list([15, 13, 8, 6, 4, 2])
print(solve_iter(L))
print(solve_rec(L))
実装のポイント
- 反復版は時間計算量 O(n)、空間計算量 O(1) で効率的に動作します。
- 再帰版のコードは簡潔ですが、リストの長さ分だけコールスタックを消費するため、空間計算量は O(n) になります。長いリストを扱う場合は、Pythonの再帰深度上限(デフォルトで約1000)にも注意が必要です。
- この実装では「現在の値が次の値以下なら未ソート」と判定しているため、隣接する値が等しい場合も
Falseとなります。つまり、厳密な降順(各要素が直前の要素より小さい)チェックになっています。
入力
[15, 13, 8, 6, 4, 2]
出力
True True
-
C++で再帰を使ったリンクリストへの挿入と走査の実装方法
整数値が与えられ、それらを使って連結リスト(リンクリスト)を構築します。ここでの課題は、再帰的なアプローチを用いて、まず単方向連結リストの末尾にノードを挿入し、その後リスト全体を走査(トラバース)して表示することです。再帰による末尾へのノード追加headがNULLの場合 → 新しいノードをheadとして追加するそれ以外の場合 → head->nextに対して再帰的に追加処理を呼び出す再帰によるノードの走査headがNULLの場合 → NULLを出力して終了するそれ以外の場合 → 現在のデータを出力し、head->nextに対して再帰的に走査を続ける実行例入力:1 - 2 - 7 -
-
C++でソート・回転済み連結リストの回転数を求める方法
問題概要ある連結リストが与えられます。このリストは、最初に昇順にソートされ、その後 K 個のノード分だけ回転(ローテーション)されたものです。この記事の目的は、元のリストに対する回転数 K を求めることです。たとえば、以下のような連結リストが入力として与えられたとします。5 → 7 → 9 → 1 → 3このリストは、元のソート済みリスト1 → 3 → 5 → 7 → 9を 2 ノード分だけ回転したものになっています。つまり、この場合の K は 2 です。具体例で理解する例 1入力: リスト: 5 → 7 → 9 → 1 → 3出力:連結リストの要素: 5 7 9 1 3ソート・回転済み連結リ