ถูกต้องหรือไม่ที่จะบอกว่าสามารถใช้การfor
วนซ้ำได้ทุกที่ และถ้าการเรียกซ้ำมักจะช้าลงเหตุผลทางเทคนิคที่เคยใช้การfor
วนซ้ำคืออะไร?
และถ้าเป็นไปได้เสมอที่จะแปลงการเรียกซ้ำเป็นfor
ลูปจะมีกฎง่ายๆในการทำหรือไม่?
ถูกต้องหรือไม่ที่จะบอกว่าสามารถใช้การfor
วนซ้ำได้ทุกที่ และถ้าการเรียกซ้ำมักจะช้าลงเหตุผลทางเทคนิคที่เคยใช้การfor
วนซ้ำคืออะไร?
และถ้าเป็นไปได้เสมอที่จะแปลงการเรียกซ้ำเป็นfor
ลูปจะมีกฎง่ายๆในการทำหรือไม่?
คำตอบ:
การเรียกซ้ำมักจะช้ากว่ามากเนื่องจากการเรียกฟังก์ชันทั้งหมดจะต้องถูกเก็บไว้ในกองซ้อนเพื่อให้สามารถย้อนกลับไปยังฟังก์ชันผู้โทรได้ ในหลายกรณีจำเป็นต้องจัดสรรและคัดลอกหน่วยความจำเพื่อใช้การแยกขอบเขต
การเพิ่มประสิทธิภาพบางอย่างเช่นการเพิ่มประสิทธิภาพการโทรหางทำให้การเรียกซ้ำเร็วขึ้น แต่ไม่สามารถทำได้เสมอไปและไม่สามารถใช้งานได้ในทุกภาษา
เหตุผลหลักในการใช้การเรียกซ้ำคือ
แน่นอนว่าการเรียกซ้ำทุกครั้งสามารถจำลองเป็นลูปได้นั่นคือสิ่งที่ CPU จะทำในท้ายที่สุด และการเรียกซ้ำเองโดยตรงหมายถึงการเรียกใช้ฟังก์ชันและขอบเขตในสแต็ก แต่การเปลี่ยนอัลกอริทึมแบบวนซ้ำของคุณเป็นแบบวนซ้ำอาจต้องใช้งานมากและทำให้โค้ดของคุณบำรุงรักษาได้น้อยลง: สำหรับการปรับให้เหมาะสมทุกครั้งควรพยายามก็ต่อเมื่อการทำโปรไฟล์หรือหลักฐานบางอย่างพบว่าจำเป็นเท่านั้น
ถูกต้องหรือไม่ที่จะบอกว่าทุกที่สามารถใช้ a for loop ได้?
ใช่เนื่องจากการเรียกซ้ำในซีพียูส่วนใหญ่ถูกจำลองด้วยลูปและโครงสร้างข้อมูลสแต็ก
และถ้าการเรียกซ้ำมักจะช้าลงเหตุผลทางเทคนิคในการใช้คืออะไร?
ไม่ใช่ "โดยปกติช้ากว่า": เป็นการเรียกซ้ำที่ใช้อย่างไม่ถูกต้องซึ่งช้ากว่า ยิ่งไปกว่านั้นคอมไพเลอร์สมัยใหม่ยังสามารถแปลงการวนซ้ำเป็นลูปได้โดยไม่ต้องถาม
และถ้าเป็นไปได้เสมอที่จะแปลงการเรียกซ้ำเป็นสำหรับลูปจะมีกฎง่ายๆในการทำหรือไม่?
เขียนโปรแกรมซ้ำสำหรับอัลกอริทึมที่เข้าใจได้ดีที่สุดเมื่ออธิบายซ้ำ ๆ เขียนโปรแกรมแบบเรียกซ้ำสำหรับอัลกอริทึมที่อธิบายได้ดีที่สุดแบบเรียกซ้ำ
ตัวอย่างเช่นการค้นหาต้นไม้ไบนารีการเรียกใช้ Quicksort และการแยกนิพจน์ในภาษาโปรแกรมต่างๆมักจะอธิบายแบบวนซ้ำ สิ่งเหล่านี้เป็นรหัสแบบวนซ้ำที่ดีที่สุดเช่นกัน ในทางกลับกันการคำนวณแฟกทอเรียลและการคำนวณตัวเลขฟีโบนักชีนั้นง่ายกว่ามากที่จะอธิบายในแง่ของการทำซ้ำ ใช้เรียกซ้ำสำหรับพวกเขาเป็นเหมือน swatting แมลงวันด้วยค้อนขนาดใหญ่: มันไม่ได้เป็นความคิดที่ดีแม้ในขณะที่ค้อนขนาดใหญ่ไม่ได้งานที่ดีจริงๆที่มัน+
และถ้าการเรียกซ้ำมักจะช้าลงเหตุผลทางเทคนิคที่เคยใช้ซ้ำสำหรับการวนซ้ำคืออะไร?
เนื่องจากในบางอัลกอริทึมนั้นยากที่จะแก้ไขซ้ำ ๆ พยายามแก้ปัญหาการค้นหาในเชิงลึกทั้งแบบวนซ้ำและแบบวนซ้ำ คุณจะเข้าใจว่าการแก้ DFS ด้วยการทำซ้ำนั้นเป็นเรื่องยาก
สิ่งที่ดีอีกอย่างที่ควรลอง: พยายามเขียน Merge sort ซ้ำ ๆ จะต้องใช้เวลาพอสมควร
ถูกต้องหรือไม่ที่จะบอกว่าทุกที่สามารถใช้ a for loop ได้?
ใช่. กระทู้นี้มีคำตอบที่ดีมากสำหรับเรื่องนี้
และถ้าเป็นไปได้เสมอที่จะแปลงการเรียกซ้ำเป็นสำหรับลูปจะมีกฎง่ายๆในการทำหรือไม่?
เชื่อฉัน. พยายามเขียนเวอร์ชันของคุณเองเพื่อแก้ปัญหาการค้นหาในเชิงลึกซ้ำ ๆ คุณจะสังเกตเห็นว่าปัญหาบางอย่างง่ายกว่าที่จะแก้ซ้ำ ๆ
คำแนะนำ: การเรียกซ้ำเป็นสิ่งที่ดีเมื่อคุณกำลังแก้ปัญหาที่สามารถแก้ไขได้ด้วยเทคนิคการหารและพิชิต
นอกจากจะช้าลงแล้วการเรียกซ้ำอาจทำให้เกิดข้อผิดพลาดสแตกล้นขึ้นอยู่กับว่ามันไปลึกแค่ไหน
ในการเขียนวิธีการเทียบเท่าโดยใช้การวนซ้ำเราต้องใช้สแต็กอย่างชัดเจน ความจริงที่ว่าเวอร์ชันซ้ำต้องใช้สแต็กสำหรับการแก้ปัญหาบ่งชี้ว่าปัญหานั้นยากพอที่จะได้รับประโยชน์จากการเรียกซ้ำ ตามกฎทั่วไปการเรียกซ้ำเหมาะสมที่สุดสำหรับปัญหาที่ไม่สามารถแก้ไขได้ด้วยจำนวนหน่วยความจำคงที่และส่งผลให้ต้องใช้สแตกเมื่อแก้ไขซ้ำ ๆ ต้องบอกว่าการเรียกซ้ำและการทำซ้ำสามารถแสดงผลลัพธ์เดียวกันได้ในขณะที่พวกเขาทำตามรูปแบบที่แตกต่างกันการตัดสินใจว่าวิธีใดทำงานได้ดีขึ้นเป็นกรณี ๆ ไปและแนวทางปฏิบัติที่ดีที่สุดคือเลือกตามรูปแบบที่เป็นปัญหาตามมา
ตัวอย่างเช่นในการหาจำนวนสามเหลี่ยมที่ n ของลำดับสามเหลี่ยม: 1 3 6 10 15 …โปรแกรมที่ใช้อัลกอริทึมแบบวนซ้ำเพื่อค้นหาจำนวนสามเหลี่ยมที่ n:
การใช้อัลกอริทึมซ้ำ:
//Triangular.java
import java.util.*;
class Triangular {
public static int iterativeTriangular(int n) {
int sum = 0;
for (int i = 1; i <= n; i ++)
sum += i;
return sum;
}
public static void main(String args[]) {
Scanner stdin = new Scanner(System.in);
System.out.print("Please enter a number: ");
int n = stdin.nextInt();
System.out.println("The " + n + "-th triangular number is: " +
iterativeTriangular(n));
}
}//enter code here
การใช้อัลกอริทึมแบบเรียกซ้ำ:
//Triangular.java
import java.util.*;
class Triangular {
public static int recursiveTriangular(int n) {
if (n == 1)
return 1;
return recursiveTriangular(n-1) + n;
}
public static void main(String args[]) {
Scanner stdin = new Scanner(System.in);
System.out.print("Please enter a number: ");
int n = stdin.nextInt();
System.out.println("The " + n + "-th triangular number is: " +
recursiveTriangular(n));
}
}
คำตอบส่วนใหญ่ดูเหมือนจะสมมติว่าiterative
= for loop
. หาก for loop ของคุณไม่ถูก จำกัด ( a la C คุณสามารถทำอะไรก็ได้ที่คุณต้องการด้วยตัวนับลูปของคุณ) แสดงว่าถูกต้อง หากเป็นลูปจริง for
(พูดในภาษา Python หรือภาษาที่ใช้งานได้ส่วนใหญ่ซึ่งคุณไม่สามารถแก้ไขตัวนับลูปได้ด้วยตนเอง) แสดงว่าไม่ถูกต้อง
ฟังก์ชันทั้งหมด (ที่คำนวณได้) สามารถใช้งานได้ทั้งแบบวนซ้ำและการใช้while
ลูป (หรือการกระโดดแบบมีเงื่อนไขซึ่งโดยพื้นฐานแล้วจะเป็นสิ่งเดียวกัน) หากคุณ จำกัด ตัวเองอย่างแท้จริงfor loops
คุณจะได้รับเพียงส่วนย่อยของฟังก์ชันเหล่านั้นเท่านั้น (ฟังก์ชันเรียกซ้ำดั้งเดิมหากการดำเนินการเบื้องต้นของคุณสมเหตุสมผล) จริงอยู่ที่มันเป็นชุดย่อยที่ค่อนข้างใหญ่ซึ่งมีทุกฟังก์ชันที่คุณน่าจะสนับสนุนในทางปฏิบัติ
สิ่งที่สำคัญกว่านั้นก็คือฟังก์ชั่นจำนวนมากนั้นง่ายมากในการใช้งานซ้ำ ๆ และยากมากที่จะนำไปใช้ซ้ำ ๆ (ไม่นับการจัดการ call stack ของคุณด้วยตนเอง)
ใช่ตามที่ธนกรณ์ตันดาวาสกล่าวไว้ ,
การเรียกซ้ำเป็นสิ่งที่ดีเมื่อคุณกำลังแก้ปัญหาที่สามารถแก้ไขได้ด้วยเทคนิคการหารและพิชิต
ตัวอย่างเช่นหอคอยแห่งฮานอย
ดูเหมือนว่าฉันจะจำได้ว่าศาสตราจารย์ด้านวิทยาการคอมพิวเตอร์ของฉันพูดย้อนกลับไปในวันนั้นว่าปัญหาทั้งหมดที่มีวิธีแก้ซ้ำยังมีวิธีแก้ปัญหาซ้ำ ๆ เขากล่าวว่าโซลูชันแบบวนซ้ำมักจะช้ากว่า แต่มักใช้เมื่อพวกเขาให้เหตุผลและเขียนโค้ดได้ง่ายกว่าโซลูชันแบบวนซ้ำ
อย่างไรก็ตามในกรณีของโซลูชันการเรียกซ้ำขั้นสูงฉันไม่เชื่อว่าจะสามารถใช้งานได้โดยใช้การfor
วนซ้ำแบบธรรมดาเสมอไป
การเรียกซ้ำ + การท่องจำอาจนำไปสู่วิธีการแก้ปัญหาที่มีประสิทธิภาพมากขึ้นเมื่อเปรียบเทียบกับวิธีการวนซ้ำที่บริสุทธิ์เช่นตรวจสอบสิ่งนี้: http://jsperf.com/fibonacci-memoized-vs-iterative-for-large-n
คำตอบสั้น ๆ : การปิดการแลกเปลี่ยนคือการเรียกซ้ำเร็วขึ้นและสำหรับลูปใช้หน่วยความจำน้อยลงในเกือบทุกกรณี อย่างไรก็ตามโดยปกติจะมีหลายวิธีในการเปลี่ยน for loop หรือการเรียกซ้ำเพื่อให้ทำงานได้เร็วขึ้น
recursion
VSiteration
?iteration = for loop
ฉันคิด.