ฉันพบความแตกต่างอื่นระหว่างวิธีการเหล่านั้น มันดูเรียบง่ายและไม่สำคัญ แต่มันมีบทบาทสำคัญมากในขณะที่คุณเตรียมตัวสำหรับการสัมภาษณ์และเรื่องนี้เกิดขึ้นดังนั้นให้มองอย่างใกล้ชิด
ในระยะสั้น: 1) การสำรวจเส้นทางการสั่งซื้อซ้ำซ้ำไม่ใช่เรื่องง่าย - ทำให้ DFT มีความซับซ้อนมากขึ้น 2) ตรวจสอบรอบได้ง่ายขึ้นด้วยการเรียกซ้ำ
รายละเอียด:
ในกรณีที่เกิดซ้ำมันง่ายต่อการสร้าง traversals ก่อนและหลัง:
ลองนึกภาพคำถามที่ค่อนข้างธรรมดา: "พิมพ์งานทั้งหมดที่ควรดำเนินการเพื่อเรียกใช้งาน 5 เมื่องานขึ้นอยู่กับงานอื่น"
ตัวอย่าง:
//key-task, value-list of tasks the key task depends on
//"adjacency map":
Map<Integer, List<Integer>> tasksMap = new HashMap<>();
tasksMap.put(0, new ArrayList<>());
tasksMap.put(1, new ArrayList<>());
List<Integer> t2 = new ArrayList<>();
t2.add(0);
t2.add(1);
tasksMap.put(2, t2);
List<Integer> t3 = new ArrayList<>();
t3.add(2);
t3.add(10);
tasksMap.put(3, t3);
List<Integer> t4 = new ArrayList<>();
t4.add(3);
tasksMap.put(4, t4);
List<Integer> t5 = new ArrayList<>();
t5.add(3);
tasksMap.put(5, t5);
tasksMap.put(6, new ArrayList<>());
tasksMap.put(7, new ArrayList<>());
List<Integer> t8 = new ArrayList<>();
t8.add(5);
tasksMap.put(8, t8);
List<Integer> t9 = new ArrayList<>();
t9.add(4);
tasksMap.put(9, t9);
tasksMap.put(10, new ArrayList<>());
//task to analyze:
int task = 5;
List<Integer> res11 = getTasksInOrderDftReqPostOrder(tasksMap, task);
System.out.println(res11);**//note, no reverse required**
List<Integer> res12 = getTasksInOrderDftReqPreOrder(tasksMap, task);
Collections.reverse(res12);//note reverse!
System.out.println(res12);
private static List<Integer> getTasksInOrderDftReqPreOrder(Map<Integer, List<Integer>> tasksMap, int task) {
List<Integer> result = new ArrayList<>();
Set<Integer> visited = new HashSet<>();
reqPreOrder(tasksMap,task,result, visited);
return result;
}
private static void reqPreOrder(Map<Integer, List<Integer>> tasksMap, int task, List<Integer> result, Set<Integer> visited) {
if(!visited.contains(task)) {
visited.add(task);
result.add(task);//pre order!
List<Integer> children = tasksMap.get(task);
if (children != null && children.size() > 0) {
for (Integer child : children) {
reqPreOrder(tasksMap,child,result, visited);
}
}
}
}
private static List<Integer> getTasksInOrderDftReqPostOrder(Map<Integer, List<Integer>> tasksMap, int task) {
List<Integer> result = new ArrayList<>();
Set<Integer> visited = new HashSet<>();
reqPostOrder(tasksMap,task,result, visited);
return result;
}
private static void reqPostOrder(Map<Integer, List<Integer>> tasksMap, int task, List<Integer> result, Set<Integer> visited) {
if(!visited.contains(task)) {
visited.add(task);
List<Integer> children = tasksMap.get(task);
if (children != null && children.size() > 0) {
for (Integer child : children) {
reqPostOrder(tasksMap,child,result, visited);
}
}
result.add(task);//post order!
}
}
โปรดทราบว่าการโพสต์ตามสั่งซ้ำ - การสำรวจเส้นทางไม่จำเป็นต้องมีการกลับรายการในภายหลัง เด็ก ๆ พิมพ์ครั้งแรกและงานของคุณในคำถามที่พิมพ์ล่าสุด ทุกอย่างปกติดี. คุณสามารถทำรายการสั่งซื้อล่วงหน้าแบบสำรวจซ้ำ (แสดงไว้ด้านบน) และรายการนั้นจะต้องมีการกลับรายการผลลัพธ์
ไม่ง่ายอย่างนั้นด้วยวิธีการวนซ้ำ! ในแนวทางแบบวนซ้ำ (หนึ่งสแต็ค) คุณสามารถทำการสั่งจองล่วงหน้าได้เท่านั้นดังนั้นคุณจำเป็นต้องย้อนกลับอาร์เรย์ผลลัพธ์ในตอนท้าย:
List<Integer> res1 = getTasksInOrderDftStack(tasksMap, task);
Collections.reverse(res1);//note reverse!
System.out.println(res1);
private static List<Integer> getTasksInOrderDftStack(Map<Integer, List<Integer>> tasksMap, int task) {
List<Integer> result = new ArrayList<>();
Set<Integer> visited = new HashSet<>();
Stack<Integer> st = new Stack<>();
st.add(task);
visited.add(task);
while(!st.isEmpty()){
Integer node = st.pop();
List<Integer> children = tasksMap.get(node);
result.add(node);
if(children!=null && children.size() > 0){
for(Integer child:children){
if(!visited.contains(child)){
st.add(child);
visited.add(child);
}
}
}
//If you put it here - it does not matter - it is anyway a pre-order
//result.add(node);
}
return result;
}
ดูง่ายใช่มั้ย
แต่มันเป็นกับดักในการสัมภาษณ์
มันหมายถึงสิ่งต่อไปนี้: ด้วยวิธีการเรียกซ้ำคุณสามารถใช้การสำรวจเส้นทางแรกและเลือกลำดับที่คุณต้องการก่อนหรือหลังการโพสต์ (เพียงแค่เปลี่ยนตำแหน่งของ "การพิมพ์" ในกรณีของ "การเพิ่มลงในรายการผลลัพธ์" ) ด้วยซ้ำ (หนึ่งสแต็ค) วิธีการที่คุณสามารถได้อย่างง่ายดายทำเพียงสั่งซื้อล่วงหน้าสำรวจเส้นทางและดังนั้นในสถานการณ์เมื่อเด็กจำเป็นต้องได้รับการตีพิมพ์ครั้งแรก (สวยมากทุกสถานการณ์เมื่อคุณต้องการเริ่มต้นการพิมพ์จากโหนดล่างจะขึ้นไป) - คุณอยู่ใน ปัญหา. หากคุณมีปัญหานั้นคุณสามารถย้อนกลับได้ในภายหลัง แต่มันจะเป็นส่วนเสริมของอัลกอริทึมของคุณ และหากผู้สัมภาษณ์กำลังดูนาฬิกาของเขามันอาจเป็นปัญหาสำหรับคุณ มีวิธีการที่ซับซ้อนในการทำการสำรวจเส้นทางที่มีการโพสต์ซ้ำตามลำดับ แต่มันไม่ง่ายไม่ง่ายตัวอย่าง:https://www.geeksforgeeks.org/iterative-postorder-traversal-using-stack/
ดังนั้นบรรทัดล่าง: ฉันจะใช้การสอบถามซ้ำในระหว่างการสัมภาษณ์มันง่ายกว่าที่จะจัดการและอธิบาย คุณมีวิธีที่ง่ายในการเปลี่ยนเส้นทางจากก่อนถึงหลังการส่งคำสั่งซื้อในกรณีเร่งด่วนใด ๆ ด้วยการวนซ้ำคุณจะไม่ยืดหยุ่น
ฉันจะใช้การสอบถามซ้ำแล้วบอกว่า: "โอเค แต่การวนซ้ำสามารถให้การควบคุมโดยตรงกับหน่วยความจำที่ใช้มากขึ้นฉันสามารถวัดขนาดสแต็คได้อย่างง่ายดายและไม่อนุญาตการล้นที่เป็นอันตราย .. "
ข้อดีอีกอย่างของการเรียกซ้ำ - มันง่ายกว่าที่จะหลีกเลี่ยง / สังเกตวงจรในกราฟ
ตัวอย่าง (preudocode):
dft(n){
mark(n)
for(child: n.children){
if(marked(child))
explode - cycle found!!!
dft(child)
}
unmark(n)
}