เทคนิคนี้เป็นอัลกอริทึม O (1) สำหรับ“ Hello World” หรือไม่


117

นี่จะจัดเป็นอัลกอริทึม O (1) สำหรับ "Hello, World!" หรือไม่ ??

public class Hello1
{
   public static void Main()
   {
      DateTime TwentyYearsLater = new DateTime(2035,01,01);
      while ( DateTime.Now < TwentyYearsLater )
      { 
          System.Console.WriteLine("It's still not time to print the hello ...");
      }
      System.Console.WriteLine("Hello, World!");
   }
}

ฉันกำลังคิดว่าจะใช้ไฟล์

DateTime TwentyYearsLater = new DateTime(2035,01,01);
while ( DateTime.Now < TwentyYearsLater )
{ 
   // ... 
}

ข้อมูลโค้ดเป็นห่วงที่ไม่ว่างที่จะใส่เป็นเรื่องตลกเมื่อใดก็ตามที่มีคนขออัลกอริทึมของความซับซ้อนบางอย่าง จะถูกต้องหรือไม่?


15
นี่คือO(N)ความซับซ้อนไม่ใช่O(1)
Fabjan

19
@SubparWebDev ไม่คุณไม่รู้ว่าจะผ่านลูปกี่ครั้งแม้ว่าคุณจะรู้เวลาที่แตกต่างกันระหว่างเวลาที่คุณเริ่มโปรแกรมกับวันที่ที่ระบุก็ตาม ขึ้นอยู่กับว่าคอมพิวเตอร์ทำงานเร็วแค่ไหนมีอะไรอีกบ้างที่ทำงานอยู่ซีพียูกำหนดเวลางานอย่างไร ฯลฯ
Servy

131
@Fabjan ไม่มีNอัลกอริทึมที่ขึ้นอยู่กับดังนั้นคุณจึงไม่สามารถพูดได้ว่าเป็นอัลกอริทึม O (N)
Servy

29
ในทางเทคนิคไม่มีข้อมูลเข้าจึงNไม่สมเหตุสมผล แต่คุณสามารถพิจารณาDateTime.Nowอินพุตที่ทำให้สิ่งนี้ยังคงขึ้นอยู่กับผลลัพธ์ หากคุณสามารถสมมติว่าเป็นค่าจริงสำหรับDateTime.Nowใช่โปรแกรมจะวนซ้ำเป็นจำนวนครั้งคงที่
โผล่

43
คำสั่งปัญหาต้องกำหนดว่า N คืออะไร
Yacoub Massad

คำตอบ:


406

สัญกรณ์ Big O ในบริบทนี้ถูกใช้เพื่ออธิบายความสัมพันธ์ระหว่างขนาดของอินพุตของฟังก์ชันและจำนวนการดำเนินการที่ต้องดำเนินการเพื่อคำนวณผลลัพธ์สำหรับอินพุตนั้น

การดำเนินการของคุณไม่มีอินพุตที่สามารถเกี่ยวข้องกับเอาต์พุตได้ดังนั้นการใช้สัญกรณ์ Big O จึงเป็นเรื่องไร้สาระ เวลาที่ดำเนินการที่จะเป็นอิสระของปัจจัยการผลิตของการดำเนินการ (ซึ่งก็คือ ... ไม่มี) เนื่องจากมีคือไม่มีความสัมพันธ์ระหว่างการป้อนข้อมูลและจำนวนของการดำเนินงานดำเนินการคุณไม่สามารถใช้ Big O เพื่ออธิบายว่ามีความสัมพันธ์ที่ไม่มีอยู่จริง


6
เกี่ยวกับอะไรO(max(1, 2035 - yearTheProgramIsStarted))?
Bergi

19
@Bergi [จริงๆแล้วไม่ใช่ [( stackoverflow.com/questions/34048740/… ) คุณไม่สามารถเพียงแค่อธิบายจำนวนการวนซ้ำของลูปตามเวลาที่คุณรันงานเท่านั้น และแน่นอนว่าคุณรวมสิ่งนั้นเข้ากับความจริงที่ว่าผู้ใช้สามารถเปลี่ยนนาฬิการะบบได้ตลอดเวลาตามที่ต้องการเป็นต้นและคุณยังไม่มีอินพุตที่มีรูปแบบที่ดีที่สามารถเกี่ยวข้องกับตัวเลขได้อย่างถูกต้อง การดำเนินการที่จำเป็นในการสร้างผลลัพธ์ Heck แม้ผลลัพธ์จะไม่สอดคล้องกัน
Servy

23
อาจโต้แย้งได้ว่าสถานะของระบบ (ซึ่งรวมถึงนาฬิกา) เป็นส่วนหนึ่งของอินพุตสำหรับโปรแกรม ในแง่นั้นคุณสามารถใช้วันที่เป็นพารามิเตอร์อินพุตได้แม้ว่าจะไม่ชัดเจนก็ตาม แม้ว่ามันจะแปลก
Connor Clark

9
เพื่อให้ชัดเจนยิ่งขึ้นอินพุต "โดยนัย" คือเดลต้าระหว่างวันที่ 1 มกราคม 2035 ถึงวันนี้
Connor Clark

6
@Hoten แต่เวลาของระบบไม่ใช่ค่าคงที่ ฟังก์ชันนี้ไม่เหมือนกับการยอมรับDateTimeเวลาเริ่มต้นเป็นอินพุต ที่ผมกล่าวว่าก่อนหน้านี้นาฬิการะบบสามารถเปลี่ยนแปลงได้ตลอดเวลา และอีกครั้งคุณไม่สามารถแมปอินพุต quazi ที่คุณกำลังอธิบายกับเอาต์พุตคงที่ได้โดยตรง ไม่มีจำนวนการดำเนินการที่ทราบสำหรับเวลาเริ่มต้นที่กำหนดหรือแม้กระทั่งสำหรับสองโปรแกรมที่ได้รับค่าที่เหมาะสมเสมอDateTime.Nowดังนั้นคุณจึงไม่สามารถเชื่อมโยงทั้งสองได้เมื่อเวลาเปลี่ยนไปเพราะคุณไม่สามารถเชื่อมโยงได้เมื่อ เวลาไม่เปลี่ยนแปลง
Servy

88

สัญกรณ์ Big-O หมายถึง 'การดำเนินการกับจำนวนงานโดยประมาณ N เวลาในการคำนวณสัดส่วนกับ N อัลกอริทึมใช้เวลาเท่าใด' เช่นการจัดเรียงอาร์เรย์ขนาด N สามารถใช้ N ^ 2, Nlog (N) เป็นต้น

สิ่งนี้ไม่มีข้อมูลอินพุตที่จะดำเนินการ O(anything)ดังนั้นจึงไม่

ยิ่งเลวร้ายลง; นี่ไม่ใช่อัลกอริทึมในทางเทคนิค อัลกอริทึมเป็นวิธีการคำนวณค่าของฟังก์ชันทางคณิตศาสตร์ - ฟังก์ชันทางคณิตศาสตร์คือการแมปจากอินพุตหนึ่งไปยังเอาต์พุต เนื่องจากสิ่งนี้ไม่ใช้อินพุตและไม่ส่งคืนอะไรเลยมันจึงไม่ใช่ฟังก์ชันในความหมายทางคณิตศาสตร์ จากวิกิพีเดีย:

อัลกอริทึมเป็นวิธีการที่มีประสิทธิภาพซึ่งสามารถแสดงได้ภายในระยะเวลาและระยะเวลาที่ จำกัด และในภาษาทางการที่กำหนดไว้อย่างดีสำหรับการคำนวณฟังก์ชัน เริ่มต้นจากสถานะเริ่มต้นและอินพุตเริ่มต้น (อาจว่างเปล่า) คำแนะนำอธิบายถึงการคำนวณที่เมื่อดำเนินการแล้วจะดำเนินการผ่านสถานะต่อเนื่องที่กำหนดไว้เป็นจำนวน จำกัด ในที่สุดก็สร้าง "เอาต์พุต" และสิ้นสุดที่สถานะสิ้นสุดสุดท้าย

นี่คืออะไรในทางเทคนิคคือระบบควบคุม จาก wikipedia;

ระบบควบคุมคืออุปกรณ์หรือชุดของอุปกรณ์ที่จัดการสั่งการสั่งการหรือควบคุมพฤติกรรมของอุปกรณ์หรือระบบอื่น ๆ

สำหรับผู้ที่ต้องการคำตอบเชิงลึกเกี่ยวกับความแตกต่างระหว่างฟังก์ชันทางคณิตศาสตร์และอัลกอริทึมและความสามารถที่ทรงพลังกว่าของคอมพิวเตอร์ในการทำสิ่งที่มีผลข้างเคียงเช่นเอาต์พุตคอนโซลการแสดงกราฟิกหรือการควบคุมโรบ็อตสามารถอ่านบทความนี้ได้ที่ สมมติฐานของศาสนจักร - ทัวริงที่แข็งแกร่ง

บทคัดย่อ

มุมมองแบบคลาสสิกของการคำนวณตำแหน่งการคำนวณเป็นการแปลงอินพุตแบบกล่องปิด (ตัวเลขเชิงเหตุผลหรือสตริง จำกัด ) เป็นเอาต์พุต ตามมุมมองเชิงโต้ตอบของการคำนวณการคำนวณเป็นกระบวนการโต้ตอบที่เกิดขึ้นอย่างต่อเนื่องแทนที่จะเป็นการแปลงอินพุตไปยังเอาต์พุตตามฟังก์ชัน โดยเฉพาะอย่างยิ่งการสื่อสารกับโลกภายนอกเกิดขึ้นระหว่างการคำนวณไม่ใช่ก่อนหรือหลัง วิธีนี้เปลี่ยนความเข้าใจของเราอย่างสิ้นเชิงเกี่ยวกับการคำนวณและวิธีการจำลองแบบ

การยอมรับปฏิสัมพันธ์ในฐานะกระบวนทัศน์ใหม่ถูกขัดขวางโดย Strong Church-Turing Thesis (SCT) ซึ่งเป็นความเชื่อที่แพร่หลายว่า Turing Machines (TMs) จับการคำนวณทั้งหมดดังนั้นแบบจำลองของการคำนวณที่แสดงออกมากกว่า TM จึงเป็นไปไม่ได้ ในบทความนี้เราแสดงให้เห็นว่า SCT ตีความวิทยานิพนธ์ของศาสนจักร - ทัวริง (CTT) ใหม่ในแบบที่ทัวริงไม่เคยตั้งใจ โดยทั่วไปสันนิษฐานว่าเทียบเท่ากับต้นฉบับเป็นตำนาน เราระบุและวิเคราะห์เหตุผลทางประวัติศาสตร์สำหรับความเชื่อที่แพร่หลายใน SCT โดยการยอมรับว่าเป็นเท็จเท่านั้นเราสามารถเริ่มใช้การโต้ตอบเป็นกระบวนทัศน์ทางเลือกของการคำนวณได้


ไม่จำเป็นต้องเป็นลำดับ เป็นเพียงการป้อนข้อมูลบางส่วนและสัญกรณ์ Landau อธิบายเวลาทำงานที่สัมพันธ์กับเมตริกบางอย่างในข้อมูลนั้นโดยทั่วไปจะเกี่ยวข้องกับขนาด
Bergi

@Bergi - ใช่เห็นประเด็นของคุณ! เพียงแค่ทำการประมาณจริงๆ แต่ใช่ - ถ้าคุณสามารถวัดปริมาณงานที่ต้องทำและจำนวนขั้นตอนที่จะไปถึงจุดนั้น big-o จะสะท้อนถึงความสัมพันธ์ของสองมาตรการนั้น ใกล้ชิด?
Steve Cooper

@kapep - มันไม่ใช่ฟังก์ชันบริสุทธิ์เพราะเป็นวิธีโมฆะ แต่ถ้าเรานับเอาท์พุทคอนโซลก็ยังสุ่ม มันสามารถแสดงผลใด ๆ ของ {"Hello, World!", "ยังไม่ถึงเวลาพิมพ์สวัสดี ... \ n สวัสดีชาวโลก!", "ยังไม่ถึงเวลาพิมพ์สวัสดี ... ยังไม่ถึงเวลาพิมพ์ สวัสดี ... \ n สวัสดีชาวโลก! ", ... }
Steve Cooper

1
การพิมพ์ไปยัง stdout ไม่ใช่เอาต์พุตใช่หรือไม่
rpax

4
@rpax ไม่ใช่ทางคณิตศาสตร์ไม่ใช่ ฟังก์ชันคือการแปลที่ไม่เปลี่ยนแปลงจากอินพุตเป็นเอาต์พุต เช่น 'กำลังสอง' เป็นฟังก์ชันที่ส่งกลับ 9 เสมอหากคุณป้อน 3 เมธอด c # เป็นเพียงฟังก์ชันคณิตศาสตร์หากการเรียกด้วยพารามิเตอร์เดียวกันจะให้ค่าผลตอบแทนเท่ากันเสมอ มิฉะนั้นหากมีผลข้างเคียงเช่นการเขียนลงคอนโซลการแสดงกราฟิกการจัดสรรหน่วยความจำสิ่งเหล่านี้ไม่ใช่ฟังก์ชันทางคณิตศาสตร์ (จะเพิ่มลิงค์ไปยังคำตอบของฉันที่ลงไปในรายละเอียดที่น่าตื่นเต้น :))
Steve Cooper

41

ไม่มีรหัสของคุณมีความซับซ้อนเวลาของการO(2^|<DeltaTime>|),

เพื่อการเข้ารหัสที่เหมาะสมของเวลาปัจจุบัน
ได้โปรดฉันขอโทษสำหรับภาษาอังกฤษของฉันก่อน

Big O คืออะไรและทำงานอย่างไรใน CS

Big O สัญกรณ์ไม่ได้ใช้ในการผูกการป้อนข้อมูลของโปรแกรมที่มีเวลาในการทำงานของตน
Big O สัญกรณ์เป็นทิ้งไว้ข้างหลังความรุนแรงวิธีการแสดงที่อัตราส่วนเชิงปริมาณของทั้งสอง

ในกรณีของการวิเคราะห์อัลกอริทึมปริมาณทั้งสองนี้ไม่ใช่อินพุต (ซึ่งอันดับแรกต้องมีฟังก์ชัน "วัด") และเวลาที่ทำงาน
พวกเขาคือความยาวของการเข้ารหัสของอินสแตนซ์ของปัญหา1และเมตริกที่น่าสนใจ

เมตริกที่ใช้กันทั่วไปคือ

  1. จำนวนขั้นตอนที่ต้องใช้ในการทำอัลกอริทึมให้สมบูรณ์ในรูปแบบการคำนวณที่กำหนด
  2. พื้นที่ที่ต้องการหากมีแนวคิดดังกล่าวอยู่โดยรูปแบบการคำนวณ

โดยปริยายจะสันนิษฐาน TM เป็นแบบจำลองเพื่อให้จุดแรกแปลกับจำนวนการใช้งานของการเปลี่ยนแปลงที่2ฟังก์ชั่นคือ "ขั้นตอน" และคนที่สองแปลว่าจำนวนของเซลล์เทปที่แตกต่างกันเป็นลายลักษณ์อักษรอย่างน้อยหนึ่งครั้ง

บ่อยครั้งที่สันนิษฐานโดยปริยายว่าเราสามารถใช้การเข้ารหัสที่เกี่ยวข้องกับพหุนามแทนการเข้ารหัสดั้งเดิมได้หรือไม่เช่นฟังก์ชันที่ค้นหาอาร์เรย์ตั้งแต่ต้นจนจบมีO(n)ความซับซ้อนแม้ว่าการเข้ารหัสอินสแตนซ์ของอาร์เรย์ดังกล่าวควรมีความยาวn*b+(n-1)ซึ่งbเป็นจำนวน (คงที่) ในสัญลักษณ์ของแต่ละองค์ประกอบ เนื่องจากbถือว่าเป็นค่าคงที่ของโมเดลการคำนวณดังนั้นนิพจน์ด้านบนและnไม่มีอาการเหมือนกัน

นอกจากนี้ยังอธิบายว่าทำไมอัลกอริทึมเช่นTrial Divisionจึงเป็นอัลกอริทึมเอกซ์โพเนนเชียลแม้ว่าโดยพื้นฐานแล้วจะเป็นfor(i=2; i<=sqr(N); i++)อัลกอริทึมที่เหมือนกัน3ก็ตาม

ดูนี้

นอกจากนี้ยังหมายความว่าสัญกรณ์ O ขนาดใหญ่อาจใช้พารามิเตอร์ได้มากเท่าที่ต้องการเพื่ออธิบายปัญหาไม่ใช่เรื่องแปลกที่จะมีพารามิเตอร์kสำหรับอัลกอริทึมบางอย่าง

ดังนั้นนี่จึงไม่เกี่ยวกับ "อินพุต" หรือ "ไม่มีอินพุต"

กรณีศึกษาตอนนี้

สัญกรณ์ Big O ไม่ได้ตั้งคำถามกับอัลกอริทึมของคุณเพียงแค่ถือว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่ โดยพื้นฐานแล้วเป็นเครื่องมือที่ใช้ได้ทุกที่แม้แต่กับอัลกอริทึมที่อาจจะยุ่งยากโดยเจตนา (เช่นของคุณ)

ในการแก้ปัญหาของคุณคุณใช้วันที่ปัจจุบันและวันที่ในอนาคตดังนั้นจึงต้องเป็นส่วนหนึ่งของปัญหาอย่างใด เพียงแค่ใส่: พวกเขาเป็นส่วนหนึ่งของตัวอย่างของปัญหา

โดยเฉพาะอินสแตนซ์คือ:

<DeltaTime>

โดย<>วิธีการใด ๆ ที่ไม่ใช่ทางพยาธิวิทยาการเข้ารหัสของทางเลือก

ดูคำชี้แจงที่สำคัญมากด้านล่าง

เวลาซับซ้อน O ขนาดใหญ่ของคุณจึงเป็นเพียงO(2^|<DeltaTime>|)เพราะคุณทำการวนซ้ำหลายครั้งซึ่งขึ้นอยู่กับค่าของเวลาปัจจุบัน ไม่มีประเด็นในการใส่ค่าคงที่เป็นตัวเลขอื่น ๆ เนื่องจากสัญกรณ์ asymptotic มีประโยชน์ในการกำจัดค่าคงที่ (ตัวอย่างเช่นการใช้O(10^|<DeltaTime>|*any_time_unit)ไม่มีจุดหมาย)

ส่วนที่ยุ่งยากอยู่ที่ไหน

เราได้ตั้งสมมติฐานที่สำคัญไว้ข้างต้นนั่นคือแบบจำลองของการคำนวณใช้เวลา5ครั้งและตามเวลาฉันหมายถึงเวลาจริง (จริง?) ไม่มีแนวคิดดังกล่าวในแบบจำลองการคำนวณมาตรฐาน TM ไม่ทราบเวลาเราเชื่อมโยงเวลากับจำนวนขั้นตอนเพราะนี่คือวิธีการทำงานจริงของเรา4 .

ในแบบจำลองของคุณอย่างไรก็ตามเวลาเป็นส่วนหนึ่งของการคำนวณคุณอาจใช้คำศัพท์เฉพาะของคนที่ใช้งานได้โดยบอกว่า Main ไม่บริสุทธิ์ แต่มีแนวคิดเหมือนกัน

เพื่อทำความเข้าใจสิ่งนี้ควรทราบว่าไม่มีอะไรป้องกันไม่ให้ Framework ใช้เวลาปลอมที่ทำงานสองครั้งห้าครั้งเร็วขึ้นสิบเท่า ด้วยวิธีนี้โค้ดของคุณจะทำงานเป็น "ครึ่ง" "หนึ่งในห้า" "หนึ่งในสิบ" ของ "เวลา"

การสะท้อนนี้มีความสำคัญต่อการเลือกการเข้ารหัส<DeltaTime>ซึ่งโดยพื้นฐานแล้วเป็นวิธีการเขียนแบบย่อ <(CurrentTime, TimeInFuture)> เนื่องจากไม่มีเวลาที่กำหนดไว้การเข้ารหัสของ CurrentTime อาจเป็นคำว่าNow (หรือทางเลือกอื่น ๆ ) เมื่อวันก่อนสามารถเข้ารหัสเป็นเมื่อวานนี้ได้โดยทำลายสมมติฐานที่ว่าความยาวของการเข้ารหัสจะเพิ่มขึ้นตามเวลาจริง ไปข้างหน้า (และหนึ่งใน DeltaTime ลดลง)

เราต้องสร้างแบบจำลองเวลาอย่างเหมาะสมในแบบจำลองการคำนวณของเราเพื่อทำสิ่งที่เป็นประโยชน์

ทางเลือกเดียวที่ปลอดภัยที่เราทำได้คือเข้ารหัสการประทับเวลาด้วยความยาวที่เพิ่มขึ้น (แต่ยังไม่ใช้ยูนารี) เมื่อเวลาทางกายภาพก้าวไปข้างหน้า นี่เป็นคุณสมบัติที่แท้จริงเพียงอย่างเดียวของเวลาที่เราต้องการและสิ่งที่การเข้ารหัสจำเป็นต้องจับ เฉพาะการเข้ารหัสประเภทนี้เท่านั้นที่อัลกอริทึมของคุณอาจให้ความซับซ้อนของเวลา

ความสับสนของคุณเกิดจากข้อเท็จจริงที่ว่าคำว่าเวลาในวลี ' ความซับซ้อนของเวลาคืออะไร?' และ ' จะใช้เวลาเท่าไหร่?' หมายถึงสิ่งที่แตกต่างกันมาก

อนิจจาคำศัพท์ใช้คำเดียวกัน แต่คุณสามารถลองใช้ "ความซับซ้อนของขั้นตอน" ในหัวของคุณแล้วถามตัวเองอีกครั้งฉันหวังว่าจะช่วยให้คุณเข้าใจคำตอบจริงๆ ^ _ ^


1นอกจากนี้ยังอธิบายถึงความจำเป็นของวิธีการแบบไม่แสดงอาการเนื่องจากแต่ละอินสแตนซ์มีความยาวที่แตกต่างกัน แต่ไม่ได้กำหนดเอง
2ฉันหวังว่าฉันจะใช้คำศัพท์ภาษาอังกฤษที่ถูกต้องที่นี่
3นี่คือสาเหตุที่เรามักจะพบlog(log(n))คำศัพท์ในคณิตศาสตร์
4 Id est ขั้นตอนต้องใช้ช่วงเวลาที่ จำกัด แต่ไม่เป็นโมฆะหรือไม่เชื่อมต่อช่วงเวลา
5ซึ่งหมายความว่าโหมดการคำนวณเป็นความรู้เกี่ยวกับเวลาทางกายภาพในนั้นซึ่งสามารถแสดงด้วยเงื่อนไขของมัน การเปรียบเทียบคือการทำงานของยาสามัญใน. NET framework


3
"เวลาวิ่งของคุณใหญ่แค่ไหน" .. ฉันแน่ใจว่าคุณหมายถึง 'big O complexity'?. นอกจากนี้เรายังสามารถเรียก 'deltaTime' ของเรา 'n' ได้ถูกต้อง .. ดังนั้นคำพูดของคุณ O (2 ^ N) จึงคล้ายกับความซับซ้อนของอัลกอริทึม Fibonacci คุณมาที่ "2 ^" ได้อย่างไร?
รอส

@ รอสขอบคุณสำหรับประเด็น ฉันมีนิสัย 2 อย่างในการทำงานกับเลขฐานสอง ประเด็นคือขั้นตอนเป็นเส้นตรงกับความยาวของการแสดงตัวเลข ฐานที่แท้จริงไม่สำคัญจริงๆและแตกต่างกันไปตามการเข้ารหัสเฉพาะ มันเป็นหลอกเชิงเส้น
Yuni Mj

ฉันขอโทษ แต่คุณช่วยอธิบายเพิ่มเติมในคำตอบของคุณได้ไหมว่าคุณสรุปความซับซ้อนได้O(2^n)อย่างไร ยังไม่ชัดเจนสำหรับผู้เริ่มต้น
Arturo Torres Sánchez

2
@YuniMj ในขณะที่เหตุผลของคุณเป็นเทคนิคที่ไม่ผิดผมคิดว่าโดยยืนยันในการวัดขนาดของDeltaTimeแทนมันคุ้มค่า , คุณเพียงแค่เพิ่มความสับสนเพิ่มเติม ตัวอย่างเช่น แต่การให้เหตุผลว่าไม่มีอัลกอริทึมการจัดเรียงที่เหมาะสมมีความซับซ้อนของเวลา $ O (n \ cdot log n) $ ทำไม? เนื่องจากคุณจะจัดเรียงเฉพาะออบเจ็กต์ที่แยกแยะได้จำนวนมากเท่านั้นซึ่งในกรณีนี้คุณสามารถใช้การจัดเรียงที่เก็บข้อมูลเพื่อจัดเรียงใน $ O (n) $ ได้เสมอ หรือขนาดวัตถุของคุณไม่ถูกผูกไว้ซึ่งในกรณีนี้ $ O (n \ cdot log n) $ จะไม่ถูกระงับเนื่องจากการเปรียบเทียบเพียงครั้งเดียวจะไม่มีเวลาคงที่อีกต่อไป ...
fgp

1
FWIW O (2 ^ n)! = O (10 ^ n) stackoverflow.com/questions/19081673/…
Nathan FD

29

แม้ว่าจะมีคำตอบที่ยอดเยี่ยมมากมายที่นี่ แต่ขอฉันเขียนใหม่ทั้งหมดสักหน่อย

Big-O โน้ตที่มีอยู่เพื่ออธิบายฟังก์ชั่น เมื่อนำไปใช้กับการวิเคราะห์อัลกอริทึมสิ่งนี้จำเป็นต้องให้เรากำหนดลักษณะบางอย่างของอัลกอริทึมนี้ในแง่ของฟังก์ชันก่อน ทางเลือกที่พบบ่อยจะพิจารณาจำนวนของขั้นตอนเป็นหน้าที่ของขนาดการป้อนข้อมูล ดังที่ระบุไว้ในคำตอบอื่น ๆ การใช้ฟังก์ชันดังกล่าวในกรณีของคุณดูเหมือนจะแปลกเพราะไม่มี "อินพุต" ที่กำหนดไว้อย่างชัดเจน เรายังสามารถลองทำได้แม้ว่า:

  • เราสามารถถือว่าอัลกอริทึมของคุณเป็นฟังก์ชันคงที่ซึ่งรับอินพุตขนาดใดก็ได้ไม่สนใจมันรอระยะเวลาที่กำหนดและเสร็จสิ้น ในกรณีนี้รันไทม์คือf (n) = constและเป็นอัลกอริทึม O (1) -time นี่คือสิ่งที่คุณคาดหวังว่าจะได้ยินใช่มั้ย? ใช่มันเป็นเทคนิคมี O
  • เราสามารถถือว่าTwentyYearsLaterพารามิเตอร์นี้เป็น "input-size" -like ที่สนใจได้ ในกรณีนี้รันไทม์คือf (n) = (nx)โดยที่xคือ "เวลานี้" ในขณะที่เรียกใช้ เมื่อเห็นแบบนี้จะเป็นอัลกอริทึมเวลา O (n) คาดหวังการโต้แย้งนี้เมื่อใดก็ตามที่คุณแสดงอัลกอริทึม O (1) ทางเทคนิคของคุณให้คนอื่นเห็น
  • โอ้ แต่รอถ้าk =TwentyYearsLaterคือการป้อนข้อมูลแล้วมันขนาด nเป็นจริงจำนวนบิตที่จำเป็นในการเป็นตัวแทนของมันคือn = บันทึก (k) พึ่งพาระหว่างขนาดของการป้อนข้อมูลที่nและรันไทม์จึงเป็นf (n) = 2 ^ n - x ดูเหมือนว่าอัลกอริทึมของคุณจะช้าอย่างทวีคูณ! ฮึ.
  • อินพุตอื่นของโปรแกรมคือกระแสของคำตอบที่ได้รับจากระบบปฏิบัติการไปยังลำดับของDateTime.Nowการเรียกใช้ในลูป เราสามารถจินตนาการได้ว่าลำดับทั้งหมดนี้ถูกจัดเตรียมไว้เป็นอินพุตในขณะที่เรารันโปรแกรม จากนั้นรันไทม์สามารถพิจารณาได้ว่าขึ้นอยู่กับคุณสมบัติของลำดับนี้นั่นคือความยาวจนถึงTwentyYearsLaterองค์ประกอบแรก ในกรณีนี้รันไทม์เป็นอีกครั้งที่f (n) = nและอัลกอริทึมคือO (n)

แต่อีกครั้งในคำถามของคุณคุณไม่ได้บอกว่าคุณสนใจรันไทม์ ถ้าคุณหมายถึงการใช้หน่วยความจำล่ะ? ขึ้นอยู่กับว่าคุณจำลองสถานการณ์อย่างไรคุณสามารถพูดได้ว่าอัลกอริทึมคือ O (1) - หน่วยความจำหรือบางที O (n) - หน่วยความจำ (หากการใช้งานDateTime.Nowจำเป็นต้องติดตามลำดับการร้องขอทั้งหมดในบางครั้ง)

และหากเป้าหมายของคุณเกิดขึ้นด้วยบางสิ่งที่ไร้สาระทำไมคุณไม่ลองทำทั้งหมดแล้วบอกว่าคุณสนใจว่าขนาดของโค้ดของอัลกอริทึมเป็นพิกเซลบนหน้าจอนั้นขึ้นอยู่กับระดับการซูมที่เลือกอย่างไร นี่อาจเป็นค่าf (ซูม) = 1 / ซูมและคุณสามารถประกาศอัลกอริทึมของคุณให้เป็นขนาดO (1 / n) -พิกเซลได้อย่างภาคภูมิใจ!


+1 ฉันเชื่อว่า "กระแสของคำตอบที่กำหนดโดยระบบปฏิบัติการต่อลำดับการDateTime.Nowเรียกใช้" เป็นอินพุตจริงที่นี่ แต่ฉันคิดว่าข้อสรุปไม่ควรเป็น O (n) แต่เป็น O (k) โดยที่ k คือความยาว จนถึงTwentyYearsLaterองค์ประกอบแรก
justhalf

7
นี่เป็นคำตอบที่ดีที่สุด - เพื่อให้ Big O มีความหมายคุณต้องใช้ความหมาย / สมมติฐานทางคณิตศาสตร์กับการนำไปใช้จริง (โดยพื้นฐานแล้วการกำหนดแบบจำลองทางคณิตศาสตร์สำหรับโปรแกรมด้วยคำจำกัดความที่มีความหมายของ "อินพุต") ในแง่นี้ความซับซ้อนของ "โปรแกรม" จะขึ้นอยู่กับความหมายที่คุณนำไปใช้ - ถ้าคุณคิดว่า N คือความแตกต่างของเวลาซึ่งสเกลเชิงเส้นกับจำนวนการดำเนินการก็คือ O (n) หากคุณถือว่าจำนวนการดำเนินการคงที่อันเป็นผลมาจากช่วงเวลาที่กำหนดก็คือ O (1)
Ant P

21

ฉันต้องไม่เห็นด้วยกับ Servy เล็กน้อย มีข้อมูลเข้าสู่โปรแกรมนี้แม้ว่าจะไม่ชัดเจนก็ตามและนั่นคือเวลาของระบบ นี่อาจเป็นความเชี่ยวชาญทางเทคนิคที่คุณไม่ได้ตั้งใจ แต่TwentyYearsFromNowตัวแปรของคุณยังไม่ถึงยี่สิบปีนับจากเวลาของระบบในตอนนี้มันถูกกำหนดให้เป็นวันที่ 1 มกราคม 2035 แบบคงที่

ดังนั้นหากคุณใช้รหัสนี้และเรียกใช้งานบนเครื่องที่มีเวลาของระบบคือวันที่ 1 มกราคม 1970 จะใช้เวลา 65 ปีจึงจะเสร็จสมบูรณ์ไม่ว่าคอมพิวเตอร์จะเร็วแค่ไหน (อาจมีการเปลี่ยนแปลงบ้างหากนาฬิกามีความผิดปกติ ) หากคุณใช้รหัสนี้และรันบนเครื่องที่มีเวลาของระบบในวันที่ 2 มกราคม 2035 รหัสนี้จะเสร็จสมบูรณ์เกือบจะในทันที

ฉันจะบอกว่าข้อมูลของคุณnคือJanuary 1st, 2035 - DateTime.Nowและเป็น O (n)

นอกจากนี้ยังมีปัญหาของจำนวนการดำเนินการ บางคนตั้งข้อสังเกตว่าคอมพิวเตอร์ที่เร็วขึ้นจะตีลูปได้เร็วขึ้นทำให้มีการทำงานมากขึ้น แต่ก็ไม่เกี่ยวข้อง เมื่อทำงานกับสัญกรณ์ big-O เราจะไม่พิจารณาความเร็วของโปรเซสเซอร์หรือจำนวนการดำเนินการที่แน่นอน หากคุณใช้อัลกอริทึมนี้และรันบนคอมพิวเตอร์แล้วรันอีกครั้ง แต่นานขึ้น 10 เท่าบนคอมพิวเตอร์เครื่องเดิมคุณคาดว่าจำนวนการดำเนินการจะเพิ่มขึ้นตามปัจจัยเดียวกันคือ 10 เท่า

สำหรับสิ่งนี้:

ฉันกำลังคิดว่าจะใช้ข้อมูลโค้ด [redacted code] เป็นห่วงที่วุ่นวายเพื่อใส่เป็นเรื่องตลกเมื่อมีคนถามอัลกอริทึมที่มีความซับซ้อนบางอย่าง จะถูกต้องหรือไม่?

ไม่ไม่จริงๆ คำตอบอื่น ๆ ครอบคลุมถึงเรื่องนี้ดังนั้นฉันแค่อยากจะพูดถึงมัน โดยทั่วไปคุณไม่สามารถเชื่อมโยงปีของการดำเนินการกับสัญกรณ์ขนาดใหญ่ใด ๆ เช่น. ไม่มีทางที่จะบอกว่า 20 ปีแห่งการประหารชีวิต = O (n ^ 87) หรืออย่างอื่นสำหรับเรื่องนั้น แม้ในอัลกอริทึมที่คุณให้ฉันสามารถเปลี่ยนเป็นTwentyYearsFromNowปี 20110, 75699436 หรือ 123456789 และ big-O ยังคงเป็น O (n)


7
เวลาไม่ใช่ข้อมูลป้อนเข้าของฟังก์ชัน แต่จะมีการเปลี่ยนแปลงสถานะตลอดเวลาซึ่งสังเกตได้ตลอดการดำเนินการของวิธีการ นาฬิการะบบสามารถแม้จะมีการเปลี่ยนแปลงในขณะที่ฟังก์ชั่นที่กำลังทำงาน เพื่อให้ Big O มีความหมายคุณจะต้องให้แต่ละอินพุตสอดคล้องกับค่าเอาต์พุต 1-1 รวมถึงการดำเนินการหลายอย่างที่จำเป็นในการคำนวณ สำหรับการดำเนินการนี้ผลลัพธ์จะไม่สอดคล้องกันแม้แต่กับอินพุตเดียวกัน (อันที่จริงมันแตกต่างกันอย่างมาก ) นอกจากจำนวนการดำเนินการที่ดำเนินการแล้วยังแตกต่างกันอย่างมาก
Servy

When working with big-O notation, we don't consider the speed of the processor or the exact number of operations.นี่เป็นข้อความเท็จ สวยมาก ๆ การดำเนินการที่เหมาะสมที่คุณจะพยายามที่จะคำนวณค่าของ Big O จะไม่เปลี่ยนจำนวนของการดำเนินงานดำเนินการบนพื้นฐานของฮาร์ดแวร์แต่คนนี้ไม่ Big O เป็นเพียงวิธีการเชื่อมโยงจำนวนการดำเนินการกับขนาดของอินพุต สำหรับการทำงานส่วนใหญ่ที่ไม่ขึ้นกับฮาร์ดแวร์ของระบบ ในกรณีนี้มันไม่ได้เป็น
Servy

If you took this algorithm and ran it on a computer, and then ran it again but for 10x longer on the same computer, you would expect the number of operations to grow by the same factor of 10x.นั่นเป็นข้อเท็จด้วย สภาพแวดล้อมไม่จำเป็นต้องเปลี่ยนจำนวนการดำเนินการในลูปแบบเชิงเส้น ตัวอย่างเช่นอาจมีโปรแกรมอื่น ๆ บนคอมพิวเตอร์ที่ใช้เวลาของ CPU มากหรือน้อยในช่วงเวลาต่างๆโดยเปลี่ยนเวลาที่ให้กับแอปพลิเคชันนี้ตลอดเวลา
Servy

ฉันอยู่กับ @Servy ในเรื่องนี้ แต่ด้วยเหตุผลที่แตกต่างกันเล็กน้อย ฟังก์ชันหลักไม่มีพารามิเตอร์และไม่ส่งกลับค่าอินพุต มันเป็นฟังก์ชันของ nil => nil ถ้าคุณต้องการ ไม่สำคัญว่าเวลาจะเป็นอย่างไรก็ยังไม่คืนอะไร
Steve Cooper

1
ถ้าเราใช้คำจำกัดความนี้ - "ในทางคณิตศาสตร์ฟังก์ชันคือความสัมพันธ์ระหว่างชุดของอินพุตและชุดของเอาต์พุตที่อนุญาตกับคุณสมบัติที่อินพุตแต่ละรายการเกี่ยวข้องกับเอาต์พุตเดียว" (วิกิพีเดีย) - และเรากำลังนับเอาท์พุทคอนโซลเป็น 'ผลลัพธ์ของฟังก์ชัน' ซึ่งจะแตกต่างกันไปขึ้นอยู่กับคอมพิวเตอร์ที่เร็วขึ้นนานขึ้นเพราะมันจะเขียนว่า "" ยังไม่ถึงเวลาพิมพ์สวัสดี ... "" บ่อยขึ้น.
Steve Cooper

13

การวิเคราะห์ Big-O เกี่ยวข้องกับจำนวนการประมวลผลที่เกี่ยวข้องเนื่องจากปริมาณข้อมูลที่ประมวลผลเพิ่มขึ้นโดยไม่มีขีด จำกัด

ที่นี่คุณกำลังจัดการกับวัตถุชิ้นเดียวที่มีขนาดคงที่เท่านั้น ด้วยเหตุนี้การใช้การวิเคราะห์ big-O จึงขึ้นอยู่กับวิธีที่คุณกำหนดคำศัพท์ของคุณ

ตัวอย่างเช่นคุณอาจหมายถึงผลงานการพิมพ์โดยทั่วไปและกำหนดให้รอนานจนข้อมูลจำนวนที่เหมาะสมจะ / จะถูกพิมพ์ในช่วงเวลาเดียวกันอย่างแม่นยำ นอกจากนี้คุณยังต้องเพิ่มคำจำกัดความที่ค่อนข้างผิดปกติ (ถ้าไม่ผิดทั้งหมด) เพื่อให้ได้ไกลมากโดยเฉพาะอย่างยิ่งการวิเคราะห์ big-O มักจะกำหนดไว้ในแง่ของจำนวนการดำเนินการพื้นฐานที่จำเป็นในการดำเนินการ งานเฉพาะ (แต่โปรดทราบว่าความซับซ้อนสามารถพิจารณาได้ในแง่ของสิ่งต่างๆเช่นการใช้หน่วยความจำไม่ใช่แค่การใช้ CPU / การดำเนินการเท่านั้น)

จำนวนของการดำเนินการขั้นพื้นฐานมักจะแปลได้ค่อนข้างใกล้เคียงกับเวลาที่ใช้ดังนั้นจึงไม่ใช่เรื่องใหญ่ที่ถือว่าทั้งสองมีความหมายเหมือนกัน อย่างไรก็ตามน่าเสียดายที่เรายังคงติดอยู่กับส่วนอื่น ๆ นั่นคือจำนวนข้อมูลที่ประมวลผลเพิ่มขึ้นโดยไม่มีขีด จำกัด ในกรณีนี้ไม่มีความล่าช้าคงที่ที่คุณกำหนดได้จะใช้งานได้จริง เพื่อให้เท่ากับ O (1) กับ O (N) คุณจะต้องกำหนดความล่าช้าที่ไม่มีที่สิ้นสุดเพื่อให้จำนวนข้อมูลคงที่จะใช้เวลาในการพิมพ์ตลอดไปเช่นเดียวกับข้อมูลจำนวนไม่ จำกัด


10

big-O สัมพันธ์กับอะไร?

ดูเหมือนคุณจะเข้าใจง่ายว่าtwentyYearsLaterเป็น "อินพุต" ถ้าคุณเขียนฟังก์ชันของคุณเป็น

void helloWorld(int years) {
   // ...
}

มันจะเป็น O (N) โดยที่ N = ปี (หรือแค่พูดO(years))

ผมจะบอกว่าอัลกอริทึมของคุณเป็น O (N) twentyYearsLater =เมื่อเทียบกับสิ่งที่เกิดขึ้นได้หมายเลขที่คุณจะเขียนในบรรทัดของรหัสที่เริ่มต้นด้วย แต่คนมักจะไม่พิจารณาตัวเลขในซอร์สโค้ดจริงเป็นอินพุต พวกเขาอาจพิจารณาอินพุตบรรทัดคำสั่งเป็นอินพุตหรืออินพุตลายเซ็นของฟังก์ชันเป็นอินพุต แต่ส่วนใหญ่จะไม่ใช่ซอร์สโค้ดเอง นั่นคือสิ่งที่คุณกำลังโต้แย้งกับเพื่อนของคุณนี่คือ "อินพุต" ใช่หรือไม่ คุณตั้งค่ารหัสของคุณเพื่อให้ดูเหมือนเป็นอินพุตโดยสังหรณ์ใจและคุณสามารถถามเวลาทำงาน O ขนาดใหญ่ของมันได้อย่างแน่นอนเกี่ยวกับหมายเลข N ในบรรทัดที่ 6 ของโปรแกรมของคุณ แต่ถ้าคุณใช้ตัวเลือกที่ไม่ใช่ค่าเริ่มต้นดังกล่าว คุณจำเป็นต้องมีความชัดเจนเกี่ยวกับข้อมูลนี้

แต่ถ้าคุณใช้อินพุตเป็นสิ่งที่ปกติกว่าเช่นบรรทัดคำสั่งหรืออินพุตไปยังฟังก์ชันจะไม่มีเอาต์พุตเลยและฟังก์ชันคือ O (1) ใช้เวลายี่สิบปี แต่เนื่องจาก big-O ไม่เปลี่ยนเป็นค่าคงที่หลายตัว O (1) = O (ยี่สิบปี)

คำถามที่คล้ายกัน - รันไทม์ของ:

void sortArrayOfSizeTenMillion(int[] array)

สมมติว่ามันทำตามที่พูดและอินพุตนั้นถูกต้องและอัลกอริทึมควบคุมการเรียงลำดับด่วนหรือฟองหรืออะไรก็ตามที่สมเหตุสมผลนั่นคือ O (1)


การเข้ารหัสอินพุตไม่ได้หมายความว่าอินพุตหายไป ไม่มีการลัดวงจรและความซับซ้อนของเวลา O (1) ในทุกกรณี bigocheatsheet.com
Theo Brinkman

@TheoBrinkman ถ้าคุณต้องการเป็นทางเทคนิคในรูปแบบเครื่องทัวริงการเข้ารหัสสิ่งที่คุณคิดเกี่ยวกับอินพุตลงในเครื่องทัวริงทำให้มันตามความหมายไม่ใช่อินพุต จากนั้นเครื่องทัวริงจะทำงานในเวลาคงที่โดยไม่ขึ้นกับอินพุตจริงใด ๆ ในบางแง่ก็ไม่ได้เรียกใช้ "การเรียงลำดับฟอง" เนื่องจากไม่ได้จัดเรียงอะไรเลยนอกจากจะดำเนินการด้วยการนำเสนอของตัวเองอย่างไรก็ตามในแง่ที่ไม่ใช่ทางเทคนิคคุณสามารถอธิบายอัลกอริทึมว่าเป็นการจัดเรียงฟองได้
djechlin

ใน 'คำศัพท์ที่ไม่ใช่ทางเทคนิค' ที่เท่าเทียมกันคุณสามารถอธิบายอัลกอริทึมที่เป็นปัญหาว่าเป็นสะพานแขวน
Theo Brinkman

@TheoBrinkman ไม่คุณทำไม่ได้ นั่นคงไม่สมเหตุสมผลกับทุกคน
djechlin

มันสมเหตุสมผลมากพอ ๆ กับการอธิบายว่ามันเป็นการเรียงฟอง O (1)
Theo Brinkman

8

"อัลกอริทึม" นี้อธิบายได้อย่างถูกต้องว่า O (1) หรือเวลาคงที่ เป็นที่ถกเถียงกันอยู่ว่าไม่มีอินพุตสำหรับโปรแกรมนี้ดังนั้นจึงไม่มี N ให้วิเคราะห์ในแง่ของ Big Oh ฉันไม่เห็นด้วยที่ไม่มีข้อมูลเข้า เมื่อคอมไพล์เป็นไฟล์ปฏิบัติการและเรียกใช้ผู้ใช้สามารถระบุอินพุตที่มีความยาวตามอำเภอใจ ความยาวอินพุตนั้นคือ N

โปรแกรมจะละเว้นอินพุต (ไม่ว่าจะมีความยาวเท่าใดก็ตาม) ดังนั้นเวลาที่ใช้ (หรือจำนวนคำสั่งของเครื่องที่ดำเนินการ) จึงเท่ากันโดยไม่คำนึงถึงความยาวของอินพุต (กำหนดให้สภาพแวดล้อมคงที่ = เวลาเริ่มต้น + ฮาร์ดแวร์) ดังนั้น O (1 )


แต่จำนวนการดำเนินการไม่จำเป็นต้องสอดคล้องกันแม้ว่าจะใช้เวลาเริ่มต้นและฮาร์ดแวร์เท่ากันก็ตาม ด้านบนของที่จะเรียกร้อง O (1) ขั้นตอนวิธีการส่งออกจะต้องมีเสมออย่างต่อเนื่องและก็ไม่ได้ก็จะแตกต่างกันอย่างดุเดือดตามเวลาเริ่มต้นและฮาร์ดแวร์ นอกจากนี้ยังสามารถเป็นอนันต์ได้อย่างง่ายดายซึ่งไม่คงที่อย่างแน่นอน นอกจากนี้ไม่มีความสัมพันธ์ระหว่างการป้อนข้อมูลที่คุณได้กำหนดไว้และจำนวนของการดำเนินงานดำเนินการ นั่นไม่ใช่ค่าคงที่ แต่ไม่ได้กำหนดไว้ คุณไม่สามารถตั้งชื่อจำนวน จำกัด และรู้ว่าจะมีการดำเนินการน้อยกว่านั้นเสมอ
Servy

เวลาจริงสูงสุดที่จะใช้คือ 20 ปี ถ้าเราจะเริ่มในอนาคตใช่ว่าจะใช้เวลานานกว่านี้ สมมติว่ามีขอบเขตล่างที่ จำกัด สำหรับระยะเวลาที่การวนซ้ำใช้เวลาและเรากำลังทำงานบนฮาร์ดแวร์แบบอนุกรม จากนั้นฉันสามารถ จำกัด จำนวนครั้งที่ลูปจะทำงานซึ่งหมายความว่าการคำนวณทั้งหมดสามารถถูกล้อมรอบด้วยฟังก์ชันคงที่ไม่ว่าข้อมูลจะมีขนาดเท่าใดก็ตาม
waldol1

Let's suppose that there is a finite lower bound on the amount of time a loop iteration takesนั่นเป็นข้อสันนิษฐานที่ผิด โปรแกรมสามารถทำงานได้ตลอดไป สิ่งที่ฉันต้องทำคือตั้งค่านาฬิการะบบของฉันเป็น 50 ปีนับจากนี้เริ่มต้นและมันจะไม่เสร็จสิ้น หรือฉันจะให้ย้ายกลับนาฬิกาเร็วกว่าที่มันเคลื่อนไปข้างหน้าหรือเริ่มต้นที่จุดเชื่อมต่อที่ไม่แน่นอนในอดีตที่ผ่านมา คุณไม่สามารถสันนิษฐานได้ว่ามีขอบเขตต่ำกว่าระยะเวลาที่โปรแกรมทำงาน มันสามารถทำงานได้ตลอดไป แต่แม้ว่าเราจะถือว่าสมมติฐาน (เท็จ) ของคุณเป็นจริงคุณก็ยังไม่สามารถเชื่อมโยงจำนวนของการดำเนินการกับอินพุตได้
Servy

การวนซ้ำแบบวนซ้ำใช้เวลา จำกัด อาจเป็นไปได้ที่จะดำเนินการเป็นจำนวนครั้งที่ไม่มีที่สิ้นสุด แต่แต่ละครั้งควรมีค่าคงที่โดยประมาณ ฉันไม่เห็นปัญหากับสมมติฐานนั้น
waldol1

โดยตรรกะนั้น [ไม่ถูกต้องโดยสิ้นเชิง] ทุก ๆ อัลกอริทึมทุกขั้นตอนจะเป็นO (1) เสมอเพราะการทำงานของแต่ละคนจะคงที่เสมอ คุณแค่แสดงให้เห็นว่าคุณไม่รู้ว่า Big O คืออะไร เป็นเครื่องมือสำหรับ (ในบริบท) ที่อธิบายความสัมพันธ์ระหว่างขนาดของอินพุตกับจำนวนการดำเนินการที่เกี่ยวข้องที่ดำเนินการ O (1) หมายถึงมีการดำเนินการจำนวนคงที่โดยไม่คำนึงถึงอินพุต ที่นี่ไม่มีการดำเนินการจำนวนคงที่โดยไม่คำนึงถึงอินพุตอาจมีการดำเนินการที่ไม่มีที่สิ้นสุดอนันต์! = ค่าคงที่
Servy

6

สิ่งหนึ่งที่ฉันประหลาดใจยังไม่ได้กล่าวถึง: สัญกรณ์ big-O คือขอบเขตบน!

ปัญหาที่ทุกคนสังเกตเห็นคือไม่มี N อธิบายอินพุตของอัลกอริทึมดังนั้นจึงไม่มีอะไรที่ต้องทำการวิเคราะห์ big-O ด้วย แต่นี้จะลดลงได้อย่างง่ายดายด้วยกลอุบายบางขั้นพื้นฐานเช่นการยอมรับint nและการพิมพ์ "Hello World" nครั้ง นั่นจะเป็นการแก้ไขข้อร้องเรียนนั้นและกลับไปที่คำถามที่แท้จริงว่าความDateTimeชั่วร้ายนั้นทำงานอย่างไร

ไม่มีการรับประกันว่าลูป while จะสิ้นสุดลง เราชอบที่จะคิดว่ามันต้องมีในบางครั้ง แต่ให้พิจารณาว่าDateTime.nowจะส่งคืนวันที่และเวลาของระบบ ไม่มีการรับประกันว่าสิ่งนี้จะเพิ่มขึ้นอย่างจำเจ เป็นไปได้ว่ามีลิงที่ได้รับการฝึกฝนทางพยาธิวิทยาบางตัวเปลี่ยนวันที่และเวลาของระบบอยู่ตลอดเวลาย้อนกลับไปเป็นวันที่ 21 ตุลาคม 2558 00:00 น. UTC จนกว่าจะมีคนให้รองเท้าและโฮเวอร์บอร์ดแบบอัตโนมัติแก่ลิง ลูปนี้สามารถทำงานได้เป็นระยะเวลาไม่ จำกัด !

เมื่อคุณเจาะลึกลงไปในนิยามทางคณิตศาสตร์ของสัญกรณ์ big-O พวกมันจะอยู่บนขอบเขต พวกเขาแสดงให้เห็นถึงสถานการณ์ที่เลวร้ายที่สุดไม่ว่าจะไม่น่าเกิดขึ้นเพียงใด สถานการณ์กรณี * ที่เลวร้ายที่สุดในที่นี้คือรันไทม์ที่ไม่มีที่สิ้นสุดดังนั้นเราจึงถูกบังคับให้ประกาศว่าไม่มีสัญกรณ์ขนาดใหญ่เพื่ออธิบายความซับซ้อนของรันไทม์ของอัลกอริทึมนี้ ไม่มีอยู่จริงเช่นเดียวกับที่ไม่มี 1/0

* แก้ไข: จากการสนทนาของฉันกับ KT มันไม่ถูกต้องเสมอไปที่จะคิดว่าสถานการณ์ที่เราสร้างแบบจำลองด้วยสัญกรณ์ขนาดใหญ่เป็นกรณีที่เลวร้ายที่สุด ในกรณีส่วนใหญ่หากบุคคลไม่สามารถระบุได้ว่าเรากำลังใช้กรณีใดอยู่พวกเขาตั้งใจที่จะสำรวจกรณีที่เลวร้ายที่สุด อย่างไรก็ตามคุณสามารถทำการวิเคราะห์ความซับซ้อนขนาดใหญ่บนรันไทม์กรณีที่ดีที่สุดได้


2
O ในความหมายคือ "ขอบเขตบน" แต่ก็ไม่ได้หมายความว่าคุณสามารถพูดถึง "ความซับซ้อนของกรณีที่เลวร้ายที่สุด" โดยใช้สัญลักษณ์ O เท่านั้น ความซับซ้อนที่คาดไว้ความซับซ้อนของกรณีที่ดีที่สุดคุณสมบัติการทำงานอื่น ๆ - ทั้งหมดนี้สามารถกล่าวถึงได้ในแง่ของขอบเขต O
KT.

@KY ความซับซ้อนของกรณีที่ดีที่สุดเรียกว่า little-o และความซับซ้อนที่คาดหวังนั้นยิ่งใหญ่ big-o เป็นความซับซ้อนของกรณีที่เลวร้ายที่สุดเสมอโดยนิยามทางคณิตศาสตร์
Cort Ammon

ไม่คุณเข้าใจผิดที่นี่ ตรวจสอบคำจำกัดความอีกครั้ง
KT.

@KT โอเคฉันจะตรวจสอบอีกครั้ง คุณตรวจสอบอีกครั้งด้วย en.wikipedia.org/wiki/Big_O_notationภายใต้ Family of Bachmann – Landau notations
Cort Ammon

ฉันคิดว่าคุณสามารถทำบางอย่างที่บ้าคลั่งเช่นใช้ฟังก์ชันfและประกาศฟังก์ชันgให้เหมือนกับfแต่ด้วยโดเมนที่ถูก จำกัด ให้รวมเฉพาะfกรณีที่ดีที่สุดจากนั้นก็ทำเรื่องใหญ่gแต่มันก็เริ่มฟังดูแย่ลงเมื่อคุณทำ ที่.
Cort Ammon

5

ความซับซ้อนใช้ในการวัด "แรงม้า" เชิงคำนวณในแง่ของเวลา / พื้นที่ สัญกรณ์ Big O ใช้เพื่อเปรียบเทียบว่าปัญหาใด "คำนวณได้" หรือ "คำนวณไม่ได้" และเพื่อเปรียบเทียบว่าโซลูชัน - อัลกอริทึม - ข้อใดดีกว่าปัญหาอื่น ๆ ดังนั้นคุณสามารถแบ่งอัลกอริทึมใด ๆ ออกเป็นสองประเภท ได้แก่ ประเภทที่แก้ไขได้ในเวลาพหุนามและประเภทที่ไม่สามารถทำได้

ปัญหาเช่น Sieve of Erathostene คือ O (n ^ exp) ดังนั้นจึงสามารถแก้ไขได้สำหรับค่าเล็ก ๆ ของ n พวกมันสามารถคำนวณได้ไม่ใช่ในเวลาพหุนาม (NP) ดังนั้นเมื่อถูกถามว่าจำนวนที่กำหนดเป็นจำนวนเฉพาะหรือไม่คำตอบขึ้นอยู่กับขนาดของจำนวนดังกล่าว ยิ่งไปกว่านั้นความซับซ้อนไม่ได้ขึ้นอยู่กับฮาร์ดแวร์ดังนั้นการมีคอมพิวเตอร์ที่เร็วขึ้นจึงไม่เปลี่ยนแปลงอะไร ...

Hello World ไม่ใช่อัลกอริทึมและด้วยเหตุนี้จึงไม่มีเหตุผลที่จะพยายามกำหนดความซับซ้อน - ซึ่งไม่มีเลย อัลกอริทึมง่ายๆอาจเป็นเช่น: กำหนดตัวเลขสุ่มให้พิจารณาว่าเป็นเลขคู่หรือคี่ ตอนนี้ตัวเลขที่ระบุมี 500 หลักหรือไม่? ไม่เพราะคุณต้องตรวจสอบว่าหลักสุดท้ายเป็นเลขคู่หรือคี่ อัลกอริทึมที่ซับซ้อนมากขึ้นคือการพิจารณาว่าตัวเลขที่กำหนดหารด้วย 3 เท่า ๆ กันหรือไม่แม้ว่าตัวเลขบางตัวจะ "ง่าย" ในการคำนวณ แต่ตัวเลขอื่น ๆ ก็ "ยาก" และนี่เป็นเพราะขนาด: เปรียบเทียบเวลาที่ใช้ในการกำหนดตัวเตือนระหว่าง ตัวเลขที่มีหนึ่งหลักและอื่น ๆ ที่มี 500 หลัก

กรณีที่ซับซ้อนมากขึ้นคือการถอดรหัสข้อความ คุณมีสัญลักษณ์อาร์เรย์แบบสุ่มที่ชัดเจนซึ่งคุณรู้ด้วยว่ากำลังถ่ายทอดข้อความสำหรับผู้ที่มีคีย์ถอดรหัส สมมติว่าผู้ส่งใช้คีย์ทางด้านซ้ายและ Hello World ของคุณจะอ่านว่า Gwkki Qieks โซลูชัน "ค้อนหัวโตไม่มีสมอง" จะสร้างชุดค่าผสมทั้งหมดสำหรับตัวอักษรเหล่านั้น: จาก Aaaa ถึง Zzzz จากนั้นค้นหาพจนานุกรมคำศัพท์เพื่อระบุว่าคำใดถูกต้องและแบ่งปันตัวอักษรทั่วไปสองตัวใน cypher (i, k) ใน ตำแหน่งเดียวกัน ฟังก์ชั่นการเปลี่ยนแปลงนี้คือสิ่งที่ Big O วัด!


4

คนส่วนใหญ่ดูเหมือนจะขาดสองสิ่งที่สำคัญมาก

  1. โปรแกรมจะมีการป้อนข้อมูล เป็นวันที่ / เวลาแบบฮาร์ดโค้ดซึ่งเทียบกับเวลาของระบบ อินพุตอยู่ภายใต้การควบคุมของบุคคลที่เรียกใช้อัลกอริทึมและเวลาของระบบไม่ใช่ สิ่งเดียวที่ผู้ใช้โปรแกรมนี้สามารถควบคุมได้คือวันที่ / เวลาที่พวกเขาได้เข้ารหัสไว้ในการเปรียบเทียบ

  2. โปรแกรมจะแตกต่างกันไปตามค่าอินพุตแต่ไม่ใช่ขนาดของชุดอินพุตซึ่งเป็นสิ่งที่สัญกรณ์ big-O เกี่ยวข้อง

ดังนั้นจึงไม่แน่นอนและสัญกรณ์ 'big-O' ที่ดีที่สุดสำหรับโปรแกรมนี้น่าจะเป็น O (null) หรืออาจเป็น O (NaN)


1
(2) แบนออกผิด โดยปกติจะพิจารณา "ความยาวของอินพุต" สำหรับรายการหรืออาร์เรย์ของออบเจ็กต์ขนาดคงที่ (เช่นจำนวนเต็ม) มันจะเป็นขนาดของชุด ในการแยกตัวประกอบจำนวนเช่น 1395195191600333 มันจะเป็นความยาวของการแทนค่าไบนารี (หรือทศนิยม ฯลฯ ) เช่นจำนวนหลัก ตามที่ระบุไว้ในคำจำกัดความของคุณใน (2) ห้ามไม่ให้ใช้ big-O เพื่อหารือเกี่ยวกับความซับซ้อนของ "findPrimeFactors (int num)" ซึ่งส่วนใหญ่นักเข้ารหัสทุกคนจะคัดค้าน
djechlin

4

ทุกคนชี้ให้เห็นอย่างถูกต้องว่าคุณไม่ได้นิยามNแต่คำตอบนั้นไม่ได้อยู่ภายใต้การตีความที่สมเหตุสมผลที่สุด ถ้าNคือความยาวของสตริงที่เรากำลังพิมพ์และ "สวัสดีชาวโลก!" เป็นเพียงตัวอย่างเนื่องจากเราอาจอนุมานจากคำอธิบายนี้ว่าอัลกอริทึม "สำหรับhello, world!" อัลกอริทึมคือ O ( N ) เนื่องจากคุณอาจมีสตริงเอาต์พุตที่ใช้เวลาพิมพ์สามสิบสี่สิบหรือห้าสิบปีและคุณ กำลังเพิ่มเวลาที่คงที่เท่านั้น O ( kN + c ) ∈ O ( N )

ภาคผนวก:

ฉันแปลกใจที่มีคนโต้แย้งเรื่องนี้ นึกถึงคำจำกัดความของ big O และ big Θ สมมติว่าเรามีอัลกอริทึมที่รอเวลาคงที่cแล้วพิมพ์ข้อความที่มีความยาวNในเวลาเชิงเส้น (นี่คือลักษณะทั่วไปของตัวอย่างโค้ดต้นฉบับ) สมมติว่าเรารอยี่สิบปีเพื่อเริ่มการพิมพ์และการพิมพ์อักขระล้านล้านตัวใช้เวลาอีกยี่สิบปี ยกตัวอย่างเช่นให้c = 20 และk = 10¹² แต่จำนวนจริงที่เป็นบวกจะทำ นั่นคืออัตราd = c / k (ในกรณีนี้คือ 2 ×10⁻¹¹) ปีต่อตัวอักษรดังนั้นเวลาดำเนินการf ( N ) ของเราจึงไม่มีอาการ dN + cปี เมื่อไรก็ตามN > k , dN = C / K N > ค ดังนั้นdN < dN + c = f ( N ) <2 dNสำหรับN > kทั้งหมดและf ( N ) ∈Θ ( N ) QED


ที่เรามี N = 13
djechlin

แต่มันไม่ได้พิมพ์แค่ "Hello world" แต่พิมพ์บรรทัด "It's still not time" ไม่ทราบจำนวน นอกจากนี้ Big O ไม่ได้ใช้เพื่อเปรียบเทียบขนาดของอินพุตกับขนาดของเอาต์พุตโดยทั่วไปจะใช้เพื่อเปรียบเทียบขนาดของอินพุตกับจำนวนการดำเนินการหรือจำนวนหน่วยความจำที่ใช้
Servy

@Servy มันเป็นหน่วยความจำที่คงที่ แต่ฉันมีขอบเขตเวลาดำเนินการโดยปริยาย ขนาดของเอาต์พุตคือ O ( N ) เช่นกันสำหรับสตริงที่กำหนดเอง: สตริงที่เราพิมพ์เมื่อถึงเวลาอาจมีขนาดใหญ่โดยพลการแม้ว่าจะเปรียบเทียบกับข้อความโปรดรอนานถึงยี่สิบปีก็ตาม
Davislor

@Servy ฉันแก้ไขเพื่อชี้แจงว่าไม่Nที่นี่ไม่ใช่ขนาดของผลลัพธ์ ฉันไม่แน่ใจว่าตัวเองสร้างความประทับใจนั้นอย่างไร แต่ฉันจะลบความคลุมเครือออกไป
Davislor

1
ดังนั้นหากคุณสมมติว่าโปรแกรมรับอินพุตเมื่อไม่เป็นเช่นนั้นเอาต์พุตอาจมีขนาดใหญ่ตามอำเภอใจเมื่อไม่สามารถลูปจะไม่ทำอะไรเลยเมื่อใดและผลลัพธ์นั้นเกี่ยวข้องกับ อินพุตเมื่อไม่เป็นเช่นนั้นใช่โปรแกรมจะเป็นแบบเส้นตรง แน่นอนว่าข้อสันนิษฐานเหล่านั้นทุกข้อล้วนเป็นเท็จทั้งหมดดังนั้นข้อสรุปที่คุณได้มาจากสิ่งเหล่านั้นจึงไม่ถือ หากคุณสามารถแสดงประเด็นของคุณได้โดยไม่ต้องตั้งสมมติฐานที่ผิดพลาดนั่นหมายความว่ามีบางอย่าง
Servy

4

ผมคิดว่าคนจะได้รับการโยนออกเพราะรหัสไม่ได้มีลักษณะเหมือนขั้นตอนวิธีการแบบดั้งเดิม นี่คือการแปลรหัสที่มีรูปแบบที่ดีกว่า แต่ยังคงเป็นจริงตามเจตนารมณ์ของคำถามของ OP

void TrolloWorld(long currentUnixTime, long loopsPerMs){
    long laterUnixTime = 2051222400000;  //unix time of 01/01/2035, 00:00:00
    long numLoops = (laterUnixTime-currentUnixTime)*loopsPerMs;

    for (long i=0; i<numLoops; i++){
        print ("It's still not time to print the hello …");
    }
    print("Hello, World!");
}

อินพุตมีความชัดเจนในขณะที่ก่อนหน้านี้จะระบุโดยปริยายตามเวลาที่โค้ดเริ่มต้นและตามความเร็วของฮาร์ดแวร์ที่รันโค้ด รหัสถูกกำหนดและมีเอาต์พุตที่กำหนดไว้อย่างดีสำหรับอินพุตที่กำหนด

เนื่องจากข้อ จำกัด ที่กำหนดไว้กับอินพุตที่เราสามารถให้ได้จึงมีขอบเขตบนของจำนวนการดำเนินการที่จะดำเนินการดังนั้นอัลกอริทึมนี้จึงเป็น O (1)


2

ณ เวลานี้ใช่

อัลกอริทึมนี้มีการป้อนข้อมูลโดยนัยกล่าวคือเวลาที่โปรแกรมเริ่มทำงานเมื่อเวลา เวลาดำเนินการจะแตกต่างกันไปในเชิงเส้น1ขึ้นอยู่กับเวลาที่เริ่มต้น ในช่วงปี 2035 และหลังจากนั้นลูป while จะออกทันทีและโปรแกรมจะสิ้นสุดลงหลังจากการดำเนินการคงที่2 . ดังนั้นอาจกล่าวได้ว่ารันไทม์คือO(max(2035 - start year, 1))3 3แต่เนื่องจากปีเริ่มต้นของเรามีค่าต่ำสุดอัลกอริทึมจะไม่ใช้เวลาเกิน 20 ปีในการดำเนินการ (เช่นค่าคงที่)

คุณสามารถทำให้อัลกอริทึมของคุณสอดคล้องกับความตั้งใจของคุณมากขึ้นโดยกำหนดDateTime TwentyYearsLater = DateTime.Now + new TimeSpan(365*20,0,0,0);4

1สิ่งนี้ถือเป็นความรู้สึกทางเทคนิคมากขึ้นของเวลาดำเนินการที่วัดเป็นจำนวนการดำเนินการเนื่องจากมีจำนวนการดำเนินการสูงสุดต่อหน่วยเวลา
2DateTime.Nowถือว่าการดึงข้อมูลเป็นการดำเนินการที่คงที่ซึ่งสมเหตุสมผล
3ฉันค่อนข้างเหยียดหยามโน้ต O ใหญ่ที่นี่เพราะเป็นฟังก์ชั่นที่ลดลงด้วยความเคารพแต่เราสามารถแก้ไขเรื่องนี้โดยแสดงมันในแง่ของstart year 4จากนั้นอัลกอริทึมจะไม่ขึ้นอยู่กับการป้อนข้อมูลโดยนัยของเวลาเริ่มต้นอีกต่อไป แต่นั่นก็ไม่เป็นผลyears prior to 2035


1

ฉันขอยืนยันว่านี่คือ O (n) โดยใช้http://www.cforcoding.com/2009/07/plain-english-explanation-of-big-o.htmlเป็นข้อมูลอ้างอิง

Big O คืออะไร?

สัญกรณ์ Big O พยายามอธิบายความซับซ้อนสัมพัทธ์ของอัลกอริทึมโดยการลดอัตราการเติบโตเป็นปัจจัยสำคัญเมื่อปัจจัยสำคัญมีแนวโน้มที่จะไม่มีที่สิ้นสุด

และ

ตัวอย่างที่ดีที่สุดของ Big-O ที่ฉันคิดได้คือการคำนวณเลขคณิต การคำนวณทางคณิตศาสตร์ขั้นพื้นฐานที่เราเรียนรู้ในโรงเรียน ได้แก่ :

ส่วนที่เพิ่มเข้าไป; การลบ; คูณ; และการหาร แต่ละสิ่งเหล่านี้เป็นการดำเนินการหรือปัญหา วิธีการแก้ปัญหาเหล่านี้เรียกว่าอัลกอริทึม

สำหรับตัวอย่างของคุณ

ให้อินพุต n = 20 (พร้อมหน่วยปี)

อัลกอริทึมคือฟังก์ชันทางคณิตศาสตร์ f () โดยที่ f () ต้องรอเป็นเวลา n ปีโดยมีสตริง "debug" อยู่ระหว่าง สเกลแฟคเตอร์คือ 1. f () สามารถลด / หรือเพิ่มได้โดยการเปลี่ยนสเกลแฟคเตอร์นี้

สำหรับกรณีนี้เอาต์พุตจะเป็น 20 เช่นกัน (การเปลี่ยนอินพุตจะเปลี่ยนเอาต์พุตเป็นเชิงเส้น)

โดยพื้นฐานแล้วฟังก์ชั่นคือ

f(n) = n*1 = n
    if  n = 20, then 
f(20) = 20 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.