যেহেতু এই উত্তরে প্রদত্ত বিদ্যমান নন-রিকার্সিভ ডিএফএস বাস্তবায়ন ভাঙ্গা বলে মনে হচ্ছে, আমাকে আসল কাজ করে যা আসলে কাজ করে।
আমি পাইথনে এটি লিখেছি, কারণ প্রয়োগের বিবরণ দিয়ে আমি এটি বেশ পঠনযোগ্য এবং কলুষিত দেখতে পেয়েছি (এবং এটির জেনারেটরyield
বাস্তবায়নের জন্য কার্যকর কীওয়ার্ড রয়েছে ) তবে এটি অন্য ভাষাগুলিতে পোর্ট করা মোটামুটি সহজ হওয়া উচিত।
# a generator function to find all simple paths between two nodes in a
# graph, represented as a dictionary that maps nodes to their neighbors
def find_simple_paths(graph, start, end):
visited = set()
visited.add(start)
nodestack = list()
indexstack = list()
current = start
i = 0
while True:
# get a list of the neighbors of the current node
neighbors = graph[current]
# find the next unvisited neighbor of this node, if any
while i < len(neighbors) and neighbors[i] in visited: i += 1
if i >= len(neighbors):
# we've reached the last neighbor of this node, backtrack
visited.remove(current)
if len(nodestack) < 1: break # can't backtrack, stop!
current = nodestack.pop()
i = indexstack.pop()
elif neighbors[i] == end:
# yay, we found the target node! let the caller process the path
yield nodestack + [current, end]
i += 1
else:
# push current node and index onto stacks, switch to neighbor
nodestack.append(current)
indexstack.append(i+1)
visited.add(neighbors[i])
current = neighbors[i]
i = 0
এই কোডটি দুটি সমান্তরাল স্ট্যাক বজায় রাখে: একটি বর্তমান পথে পূর্বের নোডগুলি সহ একটি, এবং নোড স্ট্যাকের প্রতিটি নোডের জন্য বর্তমান প্রতিবেশী সূচকযুক্ত একটি (যাতে আমরা কোনও নোডের প্রতিবেশীদের মধ্য দিয়ে পুনরায় পুনরায় পপ করার সময় পুনরাবৃত্তি শুরু করতে পারি) স্ট্যাক)। আমি একক স্ট্যাক (নোড, সূচক) জোড়া সমানভাবে ব্যবহার করতে পারতাম, তবে আমি বুঝতে পেরেছিলাম যে দ্বি-স্ট্যাক পদ্ধতিটি আরও পাঠযোগ্য এবং অন্য ভাষার ব্যবহারকারীর জন্য প্রয়োগ করা সহজতর হবে।
এই কোডটি একটি পৃথক visited
সেটও ব্যবহার করে, যা সর্বদা বর্তমান নোড এবং স্ট্যাকের যে কোনও নোড ধারণ করে, আমাকে দক্ষতার সাথে পরীক্ষা করতে দেয় যে কোনও নোড ইতিমধ্যে বর্তমান পথের অংশ কিনা। যদি আপনার ভাষার কোনও "অর্ডারযুক্ত সেট" ডেটা স্ট্রাকচার থাকে যা দক্ষ স্ট্যাকের মতো ধাক্কা / পপ অপারেশন এবং দক্ষ সদস্যপদ অনুসন্ধান উভয়ই সরবরাহ করে , আপনি নোড স্ট্যাকের জন্য এটি ব্যবহার করতে পারেন এবং পৃথক visited
সেট থেকে মুক্তি পেতে পারেন ।
বিকল্পভাবে, আপনি যদি আপনার নোডগুলির জন্য একটি কাস্টম মিউটেবল ক্লাস / কাঠামো ব্যবহার করছেন, আপনি বর্তমান নথীর অংশ হিসাবে এটি সন্ধান করা হয়েছে কিনা তা চিহ্নিত করতে প্রতিটি নোডে কেবল একটি বুলিয়ান পতাকা সংরক্ষণ করতে পারেন। অবশ্যই, এই পদ্ধতিটি আপনাকে সমান্তরালে একই গ্রাফে দুটি অনুসন্ধান চালাতে দেবে না, যদি কোনও কারণে আপনি এটি করতে চান তবে should
উপরোক্ত প্রদত্ত ফাংশনটি কীভাবে কাজ করে তা এখানে দেখানোর জন্য এখানে কিছু টেস্ট কোড রয়েছে:
# test graph:
# ,---B---.
# A | D
# `---C---'
graph = {
"A": ("B", "C"),
"B": ("A", "C", "D"),
"C": ("A", "B", "D"),
"D": ("B", "C"),
}
# find paths from A to D
for path in find_simple_paths(graph, "A", "D"): print " -> ".join(path)
প্রদত্ত উদাহরণ গ্রাফে এই কোডটি চালানো নিম্নলিখিত আউটপুট উত্পাদন করে:
এ -> বি -> সি -> ডি
ক -> খ -> ডি
এ -> সি -> বি -> ডি
এ -> সি -> ডি
মনে রাখবেন যে এই উদাহরণ গ্রাফটি পুনঃনির্দেশিত (যেমন এর সমস্ত প্রান্ত উভয় পথেই যায়), অ্যালগরিদম নির্বিচার নির্দেশিত গ্রাফগুলির জন্যও কাজ করে। উদাহরণস্বরূপ, C -> B
প্রান্তটি সরিয়ে ( B
প্রতিবেশীর তালিকা থেকে সরিয়ে দিয়ে C
) তৃতীয় পাথ ( A -> C -> B -> D
) ব্যতীত একই আউটপুট পাওয়া যায় , যা আর সম্ভব নয়।
পুনশ্চ. গ্রাফগুলি তৈরি করা সহজ, যার জন্য এই জাতীয় সরল অনুসন্ধান অ্যালগরিদমগুলি (এবং এই থ্রেডে দেওয়া অন্যান্যগুলি) খুব খারাপভাবে সম্পাদন করে।
উদাহরণস্বরূপ, অপরিবর্তিত গ্রাফে A থেকে B পর্যন্ত সমস্ত পথ সন্ধানের কাজটি বিবেচনা করুন যেখানে শুরুর নোডের দু'টি প্রতিবেশী রয়েছে: লক্ষ্য নোড বি (যার A ছাড়া অন্য কোনও প্রতিবেশী নেই) এবং একটি নোড সি যা একটি চক্রের অংশ এর মতো এন +1 নোডের:
graph = {
"A": ("B", "C"),
"B": ("A"),
"C": ("A", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
"D": ("C", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
"E": ("C", "D", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
"F": ("C", "D", "E", "G", "H", "I", "J", "K", "L", "M", "N", "O"),
"G": ("C", "D", "E", "F", "H", "I", "J", "K", "L", "M", "N", "O"),
"H": ("C", "D", "E", "F", "G", "I", "J", "K", "L", "M", "N", "O"),
"I": ("C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O"),
"J": ("C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "O"),
"K": ("C", "D", "E", "F", "G", "H", "I", "J", "L", "M", "N", "O"),
"L": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "M", "N", "O"),
"M": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "N", "O"),
"N": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "O"),
"O": ("C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"),
}
এটি সহজেই দেখতে পাওয়া যায় যে এ এবং বি এর মধ্যে একমাত্র পথ হ'ল সরাসরি, তবে নোড এ থেকে শুরু হওয়া একটি নির্দোষ ডিএফএস চক্রের মধ্যে অনর্থকভাবে পথগুলি অন্বেষণ করার জন্য ও ( এন !) সময় নষ্ট করবে , যদিও এটি স্পষ্টভাবেই (মানুষের কাছে) স্পষ্ট যে এই পাথগুলির কোনওটিই সম্ভবত বি-তে যেতে পারে না
একটি একই অনুরূপ বৈশিষ্ট্য সহ DAG গুলিও তৈরি করতে পারে, যেমন প্রারম্ভিক নোড এ সংযুক্ত লক্ষ্য নোড বি এবং অন্য দুটি নোড সি 1 এবং সি 2 দ্বারা , উভয়ই নোড ডি 1 এবং ডি 2 এর সাথে সংযুক্ত হয়, উভয়ই E এর সাথে সংযুক্ত থাকে 1 এবং E 2 , এবং আরও। জন্য এন নোড স্তর ভালো ব্যবস্থা, বি একটি থেকে সব পাথ জন্য একটি সাদাসিধা অনুসন্ধান হে (2 নষ্ট শেষ হবে এন ) সময় ছোড় আগে সব সম্ভব মৃত শেষ পরীক্ষা।
অবশ্যই, চক্রের নোডগুলির মধ্যে একটি (সি ব্যতীত) বা ডাগের শেষ স্তর থেকে লক্ষ্য নোড বিতে একটি প্রান্ত যুক্ত করা এ, বি থেকে বিস্তৃত সংখ্যক সম্ভাব্য পথ তৈরি করবে এবং একটি বিশুদ্ধরূপে স্থানীয় অনুসন্ধান অ্যালগরিদম সত্যিই আগে থেকে বলতে পারে না যে এটি এর প্রান্তটি খুঁজে পাবে কিনা। সুতরাং, এক অর্থে, এই ধরনের নির্লজ্জ অনুসন্ধানগুলির দুর্বল আউটপুট সংবেদনশীলতা গ্রাফের বৈশ্বিক কাঠামো সম্পর্কে তাদের সচেতনতার অভাবের কারণ।
যদিও বিভিন্ন প্রাক-প্রসেসিং পদ্ধতি রয়েছে (যেমন পুনরায় পাতার নোডগুলি মুছে ফেলা, একক নোড ভারটেক্স বিভাজকগুলি অনুসন্ধান করা ইত্যাদি) যা এই "ক্ষতিকারক-সময় মৃত প্রান্তগুলি" এড়াতে ব্যবহার করা যেতে পারে, আমি কোনও জেনারেল সম্পর্কে জানি না প্রিপ্রোসেসিং ট্রিক যা তাদের সকল ক্ষেত্রেই দূর করতে পারে । একটি সাধারণ সমাধান হ'ল লক্ষ্য নোডটি এখনও পৌঁছনীয় (উপ-অনুসন্ধান ব্যবহার করে) এবং ব্যাকট্র্যাকটি যদি তা না হয় তবে তাড়াতাড়ি অনুসন্ধানের প্রতিটি ধাপে পরীক্ষা করা হবে - তবে হায় আফসোস, অনুসন্ধানটি উল্লেখযোগ্যভাবে কমিয়ে দেবে (সবচেয়ে খারাপভাবে) , গ্রাফের আকারের সাথে আনুপাতিকভাবে) এমন অনেকগুলি গ্রাফের জন্য যা এ জাতীয় রোগতাত্ত্বিক মৃত প্রান্তগুলি ধারণ করে না ।