درخت برنده (و بازنده) برای ادغام k-راهه
k فهرست مرتب را با یک درخت مسابقه ادغام میکند: ریشه کوچکترین سر فهرستهاست و بعد از هر خروجی، فقط بازیهای یک مسیر برگ تا ریشه دوباره انجام میشود؛ O(log k) برای هر عضو.
k فهرست مرتب داریم (مثلاً بخشهای مرتبشدهی یک فایل بزرگ در مرتبسازی خارجی) و میخواهیم آنها را در یک فهرست مرتب ادغام کنیم. هر بار باید کوچکترین سر فهرستها را پیدا کنیم؛ مقایسهی همه O(k) است.
- زمان:
O(n log k) for n items in k runs - حافظه:
O(k) - هوروویتز–ساهنی، فصل ۵
چهار فهرست مرتب سهتایی؛ هر خروجی فقط دو بازی (log₂ ۴) را دوباره انجام میدهد و نتیجه ۱۲ عضو مرتب است.
class Node:def __init__(self, key, run):self.key = keyself.run = run # the run this key came fromself.left = Noneself.right = Noneself.parent = Nonedef k_way_merge(R):# R: k sorted runs, one per row. The leaves are the runs' current heads; each inner node holds the smaller child.k = len(R)size = 1while size < k:size = size * 2pos = [0] * sizeleaves = []for r in range(size):key = float("inf")if r < k and R[r]:key = R[r][0]leaves.append(Node(key, r))level = leaveswhile len(level) > 1:up = []for i in range(0, len(level), 2):a = level[i]b = level[i + 1]w = a if a.key <= b.key else bnode = Node(w.key, w.run)node.left = anode.right = ba.parent = nodeb.parent = nodeup.append(node)level = uproot = level[0]out = []while root.key != float("inf"):out.append(root.key)r = root.runpos[r] = pos[r] + 1leaf = leaves[r]leaf.key = R[r][pos[r]] if pos[r] < len(R[r]) else float("inf")node = leaf.parentwhile node is not None:w = node.left if node.left.key <= node.right.key else node.rightnode.key = w.keynode.run = w.runnode = node.parentreturn out
شروع اجرا
∅
متغیرهای محلی
نارنجی = در همین گام عوض شد
R list
Call stack
- k_way_merge()خط 10
توضیح
مسئله
k فهرست مرتب داریم (مثلاً بخشهای مرتبشدهی یک فایل بزرگ در مرتبسازی خارجی) و میخواهیم آنها را در یک فهرست مرتب ادغام کنیم. هر بار باید کوچکترین سر فهرستها را پیدا کنیم؛ مقایسهی همه O(k) است.
درخت برنده
یک درخت مسابقه میسازیم: برگها سر فهرستها هستند و هر گرهی داخلی برنده (کلید کوچکتر) بازی دو فرزندش است. ریشه برندهی کل است. بعد از خروجی دادن ریشه، فقط برگِ فهرست برنده عوض میشود، پس فقط بازیهای مسیر آن برگ تا ریشه دوباره انجام میشوند: ⌈log₂ k⌉ مقایسه.
درخت بازنده
در درخت برنده، برای بازی دوباره در هر گره باید سراغ هر دو فرزند برویم. در درخت بازنده هر گرهی داخلی بازندهی بازیاش را نگه میدارد و برندهی کل جداگانه نگه داشته میشود. در بازی دوباره، کلید تازه فقط با بازندهی ذخیرهشده در هر گرهی مسیر مقایسه میشود: کمتر به حافظه دسترسی دارد و در مرتبسازی خارجی ترجیح داده میشود.
ورودی
هر سطر R یک فهرست مرتب است. وقتی فهرستی تمام شد، برگش ∞ میشود.