มีระบบเบื้องหลังการวิเคราะห์อัลกอริทึมหรือไม่?


159

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

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

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

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


3
ขอขอบคุณผู้เขียนStackEdit ที่ทำให้เขียนโพสต์ยาว ๆ ได้อย่างสะดวกและผู้อ่านเบต้าของฉันFrankW , Juho , GillesและSebastian ที่ช่วยฉันแก้ไขข้อบกพร่องที่ร่างไว้ก่อนหน้านี้
ราฟาเอล

1
เฮ้ @ ราฟาเอลนี่เป็นของวิเศษ ฉันคิดว่าฉันแนะนำให้รวมกันเป็น PDF เพื่อหมุนเวียนไปรอบ ๆ ? เรื่องแบบนี้อาจเป็นข้อมูลอ้างอิงที่มีประโยชน์จริงๆ
hadsed

1
@hadsed: ขอบคุณฉันดีใจที่มีประโยชน์กับคุณ! สำหรับตอนนี้ฉันต้องการให้มีการเชื่อมโยงไปยังโพสต์นี้ อย่างไรก็ตามเนื้อหาของผู้ใช้ SE คือ "ได้รับอนุญาตภายใต้ cc by-sa 3.0 พร้อมกับการระบุแหล่งที่มา" (ดูส่วนท้ายของหน้า) เพื่อให้ทุกคนสามารถสร้าง PDF จากมันตราบใดที่มีการระบุแหล่งที่มา
ราฟาเอล

2
ฉันไม่ได้มีความสามารถโดยเฉพาะอย่างยิ่งในเรื่องนี้ แต่มันเป็นเรื่องปกติหรือเปล่าที่ไม่มีการอ้างอิงถึงทฤษฎีบทระดับปริญญาโทในแอนเวอร์ใด ๆ
babou

1
@ บาบูฉันไม่ทราบว่า "ปกติ" หมายถึงที่นี่ จากมุมมองของฉันทฤษฎีบทหลักไม่มีธุรกิจอยู่ที่นี่: นี่เป็นเรื่องเกี่ยวกับการวิเคราะห์อัลกอริทึมทฤษฎีบทต้นแบบเป็นเครื่องมือที่เฉพาะเจาะจงมากสำหรับการแก้ปัญหาที่เกิดซ้ำ (บางส่วน) เนื่องจากคณิตศาสตร์ครอบคลุมที่อื่น (เช่นที่นี่ ) ฉันเลือกที่จะครอบคลุมเฉพาะบางส่วนจากอัลกอริทึมถึงคณิตศาสตร์ที่นี่ ฉันให้การอ้างอิงถึงโพสต์ที่เกี่ยวข้องกับการทำงานคณิตศาสตร์ในคำตอบของฉัน
Raphael

คำตอบ:


134

การแปลรหัสเป็นคณิตศาสตร์

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

ตัวอย่าง: การเปรียบเทียบใน Bubblesort

พิจารณาอัลกอริธึมที่จัดเรียงอาร์เรย์ที่กำหนดA:

 bubblesort(A) do                   1
  n = A.length;                     2
  for ( i = 0 to n-2 ) do           3
    for ( j = 0 to n-i-2 ) do       4
      if ( A[j] > A[j+1] ) then     5
        tmp    = A[j];              6
        A[j]   = A[j+1];            7
        A[j+1] = tmp;               8
      end                           9
    end                             10
  end                               11
end                                 12

สมมติว่าเราต้องการทำการวิเคราะห์อัลกอริทึมการเรียงลำดับตามปกติซึ่งนับจำนวนการเปรียบเทียบองค์ประกอบ (บรรทัดที่ 5) เราทราบได้ทันทีว่าปริมาณนี้ไม่ได้ขึ้นอยู่กับเนื้อหาของอาร์เรย์Aเพียงกับความยาวของnดังนั้นเราจึงสามารถแปล (ซ้อน) - ลูปค่อนข้างเป็นผลรวม (ซ้อน) รวมกัน; ตัวแปรลูปจะกลายเป็นตัวแปรการสรุปรวมและช่วงการดำเนินการ เราได้รับ:nfor

Ccmp(n)=i=0n2j=0ni21==n(n1)2=(n2) ,

โดยที่คือค่าใช้จ่ายสำหรับการดำเนินการแต่ละบรรทัด 5 (ซึ่งเรานับ)1

ตัวอย่าง: Swaps ใน Bubblesort

ฉันจะแสดงโดยโปรแกรมย่อยที่ประกอบด้วยบรรทัดไปและโดยค่าใช้จ่ายสำหรับการดำเนินการโปรแกรมย่อยนี้ (หนึ่งครั้ง)Pi,jijCi,j

ตอนนี้ขอบอกว่าเราต้องการนับแลกเปลี่ยนที่เป็นวิธีการที่มักจะถูกดำเนินการ นี่คือ "บล็อกพื้นฐาน" ซึ่งเป็นโปรแกรมย่อยที่จะดำเนินการทางอะตอมเสมอและมีค่าใช้จ่ายคงที่ (ที่นี่ ) การทำสัญญาบล็อกดังกล่าวเป็นสิ่งที่มีประโยชน์อย่างหนึ่งที่เรามักใช้โดยไม่ต้องคิดหรือพูดถึงมันP6,81

ด้วยการแปลที่คล้ายกันข้างต้นเรามาถึงสูตรต่อไปนี้:

Cswaps(A)=i=0n2j=0ni2C5,9(A(i,j))j)})

A(i,j)หมายถึงรัฐอาเรย์ก่อนย้ำ -th ของ{5,9}(i,j)P5,9

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

เห็นได้ชัดว่าค่าใช้จ่ายของขึ้นอยู่กับเนื้อหาของ (ค่าและโดยเฉพาะ) ดังนั้นเราจึงต้องคำนึงถึงสิ่งนั้น ตอนนี้เราเผชิญกับความท้าทาย: เราจะ "แกะ"อย่างไร เราสามารถพึ่งพาเนื้อหาของอย่างชัดเจน:P5,9AA[j]A[j+1]C5,9A

C5,9(A(i,j))=C5(A(i,j))+{1,A(i,j)[j]>A(i,j)[j+1]0,else{}

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

  1. กรณีที่เลวร้ายที่สุด

    เพียงแค่ดูที่ผลรวมและสังเกตว่า , เราสามารถหาขอบเขตบนเล็กน้อยสำหรับค่าใช้จ่าย:C5,9(A(i,j)){0,1}

    Cswaps(A)i=0n2j=0ni21=n(n1)2=(n2){2}

    แต่สิ่งนี้สามารถเกิดขึ้นได้หรือไม่นั่นคือมีสำหรับขอบเขตบนนี้หรือไม่ ตามที่ปรากฎว่าใช่: ถ้าเราใส่อาเรย์เรียงขององค์ประกอบที่แตกต่างกันแบบคู่กลับกันผกผันทุกการวนซ้ำจะต้องทำการสลับ ดังนั้นเราจึงได้จำนวนบับเบิลพอร์ตที่เลวร้ายที่สุดอย่างแน่นอนA

  2. กรณีที่ดีที่สุด

    ตรงกันข้ามมีขอบเขตล่างที่น่ารำคาญ:

    Cswaps(A)i=0n2j=0ni20=00

    สิ่งนี้สามารถเกิดขึ้นได้: ในอาร์เรย์ที่เรียงลำดับแล้ว Bubblesort จะไม่ทำการสลับครั้งเดียว

  3. กรณีเฉลี่ย

    กรณีที่แย่ที่สุดและดีที่สุดเปิดช่องว่างค่อนข้าง แต่จำนวน swaps ทั่วไปคืออะไร? เพื่อที่จะตอบคำถามนี้เราจำเป็นต้องกำหนดความหมาย "ทั่วไป" ในทางทฤษฎีเราไม่มีเหตุผลที่จะชอบสิ่งใดสิ่งหนึ่งเหนือสิ่งอื่นดังนั้นเราจึงมักจะมีการแจกแจงแบบสม่ำเสมอในทุก ๆ ทางที่เป็นไปได้ เรา จำกัด ตัวเองให้อยู่ในอาร์เรย์ด้วยองค์ประกอบที่แตกต่างกันตามลำดับและสมมติว่าเป็นแบบจำลองการเปลี่ยนแปลงแบบสุ่ม

    จากนั้นเราสามารถเขียนค่าใช้จ่ายเช่นนี้²:

    E[Cswaps]=1n!Ai=0n2j=0ni2C5,9(A(i,j))

    ตอนนี้เราต้องไปไกลกว่าการจัดการกับผลรวมอย่างง่าย โดยการดูอัลกอริทึมเราทราบว่าการสลับทุกครั้งจะลบการผกผันเดียวใน (เราเพียงแค่สลับneighbours³) นั่นคือจำนวนของสัญญาแลกเปลี่ยนดำเนินการในเป็นว่าจำนวน inversionsของ ดังนั้นเราสามารถแทนที่ผลรวมสองภายในและรับAAinv(A)A

    E[Cswaps]=1n!Ainv(A)(A)

    โชคดีที่เรามีจำนวนผู้รุกรานโดยเฉลี่ยที่พิจารณาแล้วว่าเป็น

    E[Cswaps]=12(n2)

    ซึ่งเป็นผลสุดท้ายของเรา โปรดทราบว่านี่เป็นครึ่งราคาที่เลวร้ายที่สุด


  1. โปรดทราบว่าอัลกอริทึมได้รับการกำหนดอย่างรอบคอบเพื่อให้การวนซ้ำ "ครั้งสุดท้าย" i = n-1ของลูปด้านนอกที่ไม่เคยทำสิ่งใด ๆ
  2. " " เป็นสัญลักษณ์ทางคณิตศาสตร์สำหรับ "ค่าที่คาดหวัง" ซึ่งนี่เป็นค่าเฉลี่ยE
  3. เราเรียนรู้ไปตามวิธีที่ไม่มีอัลกอริทึมที่แลกเปลี่ยนองค์ประกอบใกล้เคียงเท่านั้นที่สามารถ asymptotically เร็วกว่า Bubblesort (แม้โดยเฉลี่ย) - จำนวนการรุกรานนั้นมีขอบเขตต่ำกว่าสำหรับอัลกอริธึมดังกล่าวทั้งหมด นี้นำไปใช้เช่นการแทรกเรียงและการเลือกเรียง

วิธีการทั่วไป

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

เราแสดงสถานะปัจจุบันด้วย (ลองจินตนาการว่ามันเป็นชุดของการกำหนดตัวแปร) เมื่อเรารันโปรแกรมที่เริ่มต้นใน stateเราจะสิ้นสุดใน state ( ถูกยกเลิก)ψPψψ/PP

  • งบส่วนบุคคล

    รับเพียงคำเดียวS;, คุณกำหนดค่าใช้จ่ายปอนด์ต่อตารางนิ้ว) โดยทั่วไปจะเป็นฟังก์ชันคงที่CS(ψ)

  • การแสดงออก

    หากคุณมีการแสดงออกEของแบบฟอร์มE1 ∘ E2(พูดการแสดงออกทางคณิตศาสตร์ที่อาจจะเพิ่มหรือการคูณคุณจะเพิ่มค่าใช้จ่ายซ้ำ:

    CE(ψ)=c+CE1(ψ)+CE2(ψ)ปอนด์ต่อตารางนิ้ว)

    สังเกตได้ว่า

    • ค่าใช้จ่ายในการดำเนินงานอาจไม่คงที่ แต่ขึ้นอยู่กับค่าของและและcE1E2
    • การประเมินผลของนิพจน์อาจเปลี่ยนแปลงสถานะในหลายภาษา

    ดังนั้นคุณอาจต้องยืดหยุ่นกับกฎนี้

  • ลำดับ

    เมื่อให้โปรแกรมPเป็นลำดับของโปรแกรมQ;Rคุณจะต้องเพิ่มค่าใช้จ่าย

    CP(ψ)=CQ(ψ)+CR(ψ/Q){Q})

  • เงื่อนไข

    ให้โปรแกรมPของแบบฟอร์มif A then Q else R endค่าใช้จ่ายขึ้นอยู่กับสถานะ:

    CP(ψ)=CA(ψ)+{CQ(ψ/A),A evaluates to true under ψCR(ψ/A),else

    โดยทั่วไปการประเมินAอาจเปลี่ยนแปลงสถานะได้ดีดังนั้นการอัพเดทค่าใช้จ่ายของแต่ละสาขา

  • สำหรับลูป

    รับโปรแกรมPของแบบฟอร์มfor x = [x1, ..., xk] do Q endกำหนดค่าใช้จ่าย

    CP(ψ)=cinit_for+i=1kcstep_for+CQ(ψi{x:=xi})

    ที่เป็นรัฐก่อนการประมวลผลสำหรับค่าคือหลังจากที่ซ้ำกับที่ถูกตั้งค่าให้, ... ,ψiQxixx1xi-1

    สังเกตค่าคงที่พิเศษสำหรับการบำรุงรักษาลูป ต้องสร้างตัวแปรลูป ( ) และกำหนดค่า ( ) สิ่งนี้มีความเกี่ยวข้องตั้งแต่cinit_forcstep_for

    • การคำนวณครั้งต่อไปxiอาจมีค่าใช้จ่ายสูงและ
    • - forลูปที่มีเนื้อความว่างเปล่า (เช่นหลังจากทำให้การตั้งค่าที่ดีที่สุดในกรณีที่ง่ายที่สุดด้วยค่าใช้จ่ายเฉพาะ) ไม่มีค่าใช้จ่ายใด ๆ หากมันทำการวนซ้ำ
  • ในขณะที่ลูป

    รับโปรแกรมPของแบบฟอร์มwhile A do Q endกำหนดค่าใช้จ่าย

    CP(ψ) =CA(ψ)+{0,A evaluates to false under ψCQ(ψ/A)+CP(ψ/A;Q), else

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

    ตัวอย่าง:พิจารณาอัลกอริธึมสั้น ๆ นี้:

    while x > 0 do    1
      i += 1          2
      x = x/2         3
    end               4
    

    โดยการใช้กฎเราจะได้รับ

    C1,4({i:=i0;x:=x0}) =c<+{0,x00c+=+c/+C1,4({i:=i0+1;x:=x0/2}), else

    ด้วยค่าใช้จ่ายคงที่บางรายการสำหรับแต่ละข้อความสั่ง เราถือว่าโดยปริยายว่าสิ่งเหล่านี้ไม่ได้ขึ้นอยู่กับสถานะ (ค่าของและ); สิ่งนี้อาจจะใช่หรือไม่ใช่จริงใน "ความจริง": คิดว่าล้น!cix

    ตอนนี้เราต้องแก้ปัญหาการเกิดซ้ำนี้{1,4} เราทราบว่าจำนวนการทำซ้ำไม่ใช่ค่าใช้จ่ายของลูปบอดี้นั้นขึ้นอยู่กับค่าของดังนั้นเราจึงสามารถวางได้ เราถูกทิ้งให้อยู่กับการเกิดซ้ำนี้:C1,4i

    C1,4(x)={c>,x0c>+c+=+c/+C1,4(x/2), else

    นี้แก้ด้วยวิธีการประถมศึกษาเพื่อ

    C1,4(ψ)=log2ψ(x)(c>+c+=+c/)+c> ,

    แนะนำสถานะเต็มรูปแบบให้เป็นสัญลักษณ์ ถ้าแล้ว5ψ={,x:=5,}ψ(x)=5

  • ขั้นตอนการโทร

    รับโปรแกรมPของฟอร์มM(x)สำหรับพารามิเตอร์บางตัวโดยxที่Mโพรซีเดอร์ที่มีพารามิเตอร์ (ตั้งชื่อ) pกำหนดค่าใช้จ่าย

    CP(ψ)=ccall+CM(ψglob{p:=x})\})

    โปรดทราบอีกครั้งว่าค่าคงที่พิเศษ (ซึ่งอันที่จริงแล้วขึ้นอยู่กับ !) การเรียกใช้โปรซีเจอร์นั้นมีราคาแพงเนื่องจากวิธีการใช้งานบนเครื่องจริงและบางครั้งก็ควบคุมการรันไทม์ (เช่นการประเมินจำนวนฟีโบนัชชีซ้ำ ๆ อย่างไร้เดียงสา)ccallψ

    ฉันแก้ไขปัญหาทางความหมายบางอย่างที่คุณอาจมีกับรัฐที่นี่ คุณจะต้องการแยกแยะสถานะโกลบอลและโลคอลการเรียกโพรซีเดอร์ ขอเพียงถือว่าเราผ่านรัฐเดียวทั่วโลกที่นี่และMได้รับรัฐท้องถิ่นใหม่เริ่มต้นได้โดยการตั้งค่าของการp xนอกจากนี้xอาจเป็นนิพจน์ที่เรา (ปกติ) คิดว่าจะได้รับการประเมินก่อนส่ง

    ตัวอย่าง:พิจารณาขั้นตอน

    fac(n) do                  
      if ( n <= 1 ) do         1
        return 1               2
      else                     3
        return n * fac(n-1)    4
      end                      5
    end                        
    

    ตามกฎเราได้รับ:

    Cfac({n:=n0})=C1,5({n:=n0})=c+{C2({n:=n0}),n01C4({n:=n0}), else=c+{creturn,n01creturn+c+ccall+Cfac({n:=n01}), else

    โปรดทราบว่าเราไม่สนใจสถานะโลกเนื่องจากfacเห็นได้ชัดว่าไม่สามารถเข้าถึงได้ การเกิดซ้ำโดยเฉพาะนี้ง่ายต่อการแก้ไข

    Cfac(ψ)=ψ(n)(c+creturn)+(ψ(n)1)(c+ccall)

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

หากคุณคิดว่าตอนนี้มันซับซ้อนเกินกว่าจะได้รับคำแนะนำ: มันคือ ! การได้รับต้นทุนที่แน่นอนของอัลกอริทึมในแบบจำลองใด ๆ ที่อยู่ใกล้กับเครื่องจักรจริงเพื่อเปิดใช้งานการคาดการณ์แบบรันไทม์ และนั่นไม่ได้พิจารณาถึงการแคชและผลกระทบที่น่ารังเกียจอื่น ๆ ในเครื่องจริง

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

หมายเหตุเกี่ยวกับค่าใช้จ่ายที่เชิงเส้นกำกับ

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

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

นี่คือวิธีการวิเคราะห์เชิงความสัมพันธ์กับวิธีการนี้

  1. ระบุการดำเนินการที่โดดเด่น (ที่ชักจูงต้นทุน) นั่นคือการดำเนินการที่เกิดขึ้นบ่อยที่สุด (สูงถึงปัจจัยคงที่) ในตัวอย่างของ Bubblesort หนึ่งทางเลือกที่เป็นไปได้คือการเปรียบเทียบในบรรทัดที่ 5

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

  2. ทำการวิเคราะห์โดยใช้จำนวนการดำเนินการของการดำเนินการนี้เป็นต้นทุน
  3. เมื่อลดความซับซ้อนให้ประมาณการ ใช้ความระมัดระวังเพื่อให้การประมาณการจากด้านบนหากเป้าหมายของคุณเป็นขอบเขตสูงสุด ( ) resp จากด้านล่างหากคุณต้องการลดขอบเขต ( )OΩ

ให้แน่ใจว่าคุณเข้าใจความหมายของสัญลักษณ์กุ๊บ โปรดจำไว้ว่าขอบเขตดังกล่าวอยู่สำหรับทั้งสามกรณี ; การใช้ไม่ได้แปลว่าเป็นกรณีที่เลวร้ายที่สุดO

อ่านเพิ่มเติม

มีความท้าทายและลูกเล่นเพิ่มเติมในการวิเคราะห์อัลกอริทึม นี่คือคำแนะนำในการอ่าน

มีคำถามมากมายที่ติดแท็กโดยใช้เทคนิคที่คล้ายกับสิ่งนี้


1
อาจมีการอ้างอิงและตัวอย่างบางส่วนถึงทฤษฎีบทหลัก (และส่วนขยาย ) สำหรับการวิเคราะห์เชิงเส้น
Nikos M.

@NikosM มันอยู่นอกขอบเขตที่นี่ (ดูความเห็นเกี่ยวกับคำถามข้างต้น) โปรดทราบว่าฉันเชื่อมโยงไปยังโพสต์อ้างอิงของเราเกี่ยวกับการแก้ไขการเกิดซ้ำซึ่งนำเสนอทฤษฎีบทต้นแบบและคณะ
ราฟาเอล

@ Nikos M: $ 0.02 ของฉัน: ในขณะที่ทฤษฎีบทหลักที่ทำงานสำหรับการเกิดซ้ำหลายครั้งมันจะไม่ให้คนอื่น ๆ อีกมากมาย มีวิธีการมาตรฐานสำหรับการแก้ไขการเกิดซ้ำ และมีอัลกอริธึมที่เราจะไม่มีแม้แต่การเกิดซ้ำที่ให้เวลาทำงาน อาจจำเป็นต้องใช้เทคนิคการนับขั้นสูงบางอย่าง สำหรับคนที่มีภูมิหลังทางคณิตศาสตร์ที่ดีฉันแนะนำหนังสือ "Sedgewick" ของการวิเคราะห์อัลกอริทึม "Sedgewick และ Flajolet" ซึ่งมีบทต่างๆเช่น โครงสร้างข้อมูลปรากฏเป็นตัวอย่างเป็นครั้งคราวและให้ความสำคัญกับวิธีการ!
Jay

@ ราฟาเอลฉันไม่สามารถพูดถึงเว็บใด ๆ สำหรับวิธีการ "แปลรหัสเป็นคณิตศาสตร์" นี้ขึ้นอยู่กับความหมายในการดำเนินงาน คุณสามารถให้การอ้างอิงใด ๆ กับหนังสือกระดาษหรือบทความที่เกี่ยวข้องกับเรื่องนี้อย่างเป็นทางการมากขึ้นได้ไหม? หรือในกรณีที่คุณพัฒนาขึ้นคุณมีอะไรที่ลึกซึ้งมากกว่านี้หรือไม่?
Wyvern666

1
@ Wyvern666 น่าเสียดายที่ไม่มี ฉันทำมันด้วยตัวเองเท่าที่ใคร ๆ ก็อ้างได้ว่าทำสิ่งนี้ บางทีฉันอาจจะเขียนงานอ้างอิงบางอย่างด้วยตัวเอง ที่กล่าวว่าคลังงานทั้งหมดของการวิเคราะห์เชิง combinatorics (Flajolet, Sedgewick และอื่น ๆ อีกมากมาย) เป็นรากฐานของสิ่งนี้ พวกเขาไม่ได้ใส่ใจกับความหมายอย่างเป็นทางการของ "รหัส" ส่วนใหญ่ แต่พวกเขาให้คณิตศาสตร์เพื่อจัดการกับค่าใช้จ่ายเพิ่มเติมของ "อัลกอริทึม" โดยทั่วไป ฉันคิดอย่างตรงไปตรงมาว่าแนวคิดที่วางไว้ที่นี่ไม่ลึกนัก - คณิตศาสตร์ที่คุณสามารถเข้าใจได้คือ
กราฟิลส์

29

การดำเนินการนับงบ

มีวิธีการอื่นที่ได้รับการสนับสนุนจาก Donald E. Knuth ในซีรี่ส์The Art of Computer Programming ตรงกันข้ามกับการแปลอัลกอริธึมทั้งหมดให้เป็นสูตรเดียวมันทำงานได้อย่างอิสระจากซีแมนทิกส์ของรหัสในด้าน "การรวมสิ่งต่าง ๆ เข้าด้วยกัน" และอนุญาตให้ไปในระดับต่ำกว่าเมื่อจำเป็นเท่านั้นโดยเริ่มจากมุมมอง "อินทรีอินทรี" ทุกคำสั่งสามารถวิเคราะห์ได้อย่างอิสระจากส่วนที่เหลือนำไปสู่การคำนวณที่ชัดเจนยิ่งขึ้น อย่างไรก็ตามเทคนิคการยืมรหัสตัวเองค่อนข้างดีรหัสหลอกระดับไม่สูง

วิธีการ

มันค่อนข้างง่ายในหลักการ:

  1. กำหนดชื่อ / หมายเลขให้ทุกชุดคำสั่ง
  2. กำหนดคำสั่งทุกค่าใช้จ่ายบางส่วนC_iSiCi
  3. ตรวจสอบงบทุกจำนวนครั้งของการประหารชีวิตe_iSiei
  4. คำนวณค่าใช้จ่ายทั้งหมด

    C=ieiCiC_i

คุณสามารถแทรกการประมาณและ / หรือปริมาณเชิงสัญลักษณ์ ณ จุดใดก็ได้ การสรุปผลให้สอดคล้อง

โปรดทราบว่าขั้นตอนที่ 3 อาจซับซ้อนโดยพลการ ปกติแล้วคุณจะต้องทำงานกับ (asymptotic) การประมาณเช่น " " เพื่อรับผลลัพธ์e77O(nlogn)

ตัวอย่าง: การค้นหาความลึกครั้งแรก

พิจารณาอัลกอริธึมกราฟการสำรวจเส้นทางต่อไปนี้:

dfs(G, s) do
  // assert G.nodes contains s
  visited = new Array[G.nodes.size]     1
  dfs_h(G, s, visited)                  2
end 

dfs_h(G, s, visited) do
  foo(s)                                3
  visited[s] = true                     4

  v = G.neighbours(s)                   5
  while ( v != nil ) do                 6
    if ( !visited[v] ) then             7
      dfs_h(G, v, visited)              8
    end
    v = v.next                          9
  end
end

เราคิดว่า (ไม่มีทิศทาง) กราฟจะได้รับจากรายการถ้อยคำบนโหน\} ให้เป็นจำนวนขอบ{0,,n1}m

เพียงแค่ดูที่อัลกอริทึมเราจะเห็นว่าคำสั่งบางคำสั่งถูกดำเนินการอย่างเท่าเทียมกันบ่อยครั้งเหมือนกับข้อความอื่น ๆ เราแนะนำตัวยึดตำแหน่ง ,และสำหรับการดำเนินการนับ :ABCei

i123456789eiAABBBB+CCB1C

โดยเฉพาะอย่างยิ่งเนื่องจากการเรียกซ้ำทั้งหมดในสาย 8 ทำให้เกิดการโทรในบรรทัดที่ 3 (และสายหนึ่งเกิดจากการโทรเดิม) นอกจากนี้เนื่องจากเงื่อนไขจะต้องมีการตรวจสอบหนึ่งครั้งต่อการทำซ้ำ แต่อีกครั้งเพื่อที่จะออกจากมันe8=e31foodfse6=e5+e7while

เป็นที่ชัดเจนว่า 1 ตอนนี้ในระหว่างการพิสูจน์ความถูกต้องเราจะแสดงให้เห็นว่ามีการดำเนินการเพียงครั้งเดียวต่อโหนด ว่ามีที่n แต่จากนั้นเราจะวนซ้ำทุกรายการคำคุณศัพท์หนึ่งครั้งและทุกขอบหมายถึงสองรายการทั้งหมด (หนึ่งรายการสำหรับแต่ละโหนดของเหตุการณ์); เราได้รับการทำซ้ำโดยรวม เมื่อใช้สิ่งนี้เราจะได้รับตารางต่อไปนี้:A=1fooB=nC=2m

i123456789ei11nnn2m+n2mn12m

สิ่งนี้ทำให้เรามีค่าใช้จ่ายทั้งหมดอย่างแน่นอน

C(n,m)=(C1+C2C8)+ n(C3+C4+C5+C6+C8)+ 2m(C6+C7+C9).

ด้วยการทำให้ค่าที่เหมาะสมสำหรับนั้นสามารถทำให้เรามีต้นทุนที่เป็นรูปธรรมมากขึ้น ตัวอย่างเช่นหากเราต้องการนับการเข้าถึงหน่วยความจำ (ต่อคำ) เราจะใช้Ci

i123456789Cin00110101

และรับ

Cmem(n,m)=3n+4m4m

อ่านเพิ่มเติม

ดูที่ด้านล่างของคำตอบอื่น ๆ ของฉัน


8

การวิเคราะห์อัลกอริทึมเช่นทฤษฎีบทพิสูจน์เป็นส่วนใหญ่ศิลปะ (เช่นมีโปรแกรมง่าย ๆ (เช่นปัญหา Collatz ) ที่เราไม่ทราบวิธีการวิเคราะห์) เราสามารถแปลงปัญหาความซับซ้อนของอัลกอริทึมให้เป็นคณิตศาสตร์ได้ดังที่ Raphael ได้คำตอบอย่างละเอียดแต่จากนั้นเพื่อแสดงขอบเขตของต้นทุนของอัลกอริทึมในแง่ของฟังก์ชันที่เรารู้จัก

  1. ใช้เทคนิคที่เรารู้จักจากการวิเคราะห์ที่มีอยู่เช่นการหาขอบเขตตามการเกิดซ้ำที่เราเข้าใจหรือรวม / อินทิกรัลที่เราสามารถคำนวณได้
  2. เปลี่ยนอัลกอริทึมเป็นสิ่งที่เรารู้วิธีวิเคราะห์
  3. มาด้วยวิธีการใหม่ที่สมบูรณ์แบบ

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

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

4
@ ราฟาเอลอารีย์กำลังพูดถึงการสร้างฟังก์ชันที่จำได้ว่าเป็นขอบเขตแทนที่จะเป็น "จำนวนคำสั่งที่ดำเนินการโดยโปรแกรม" (ซึ่งเป็นคำตอบของคุณ) กรณีทั่วไปเป็นงานศิลปะ - ไม่มีอัลกอริทึมที่สามารถเกิดขึ้นกับขอบเขตที่ไม่สำคัญสำหรับอัลกอริทึมทั้งหมด อย่างไรก็ตามกรณีทั่วไปเป็นชุดของเทคนิคที่รู้จัก (เช่นทฤษฎีบทหลัก)
Gilles

@Gilles หากทุกอย่างที่ไม่มีอัลกอริธึมเป็นศิลปะช่างฝีมือ (โดยเฉพาะโปรแกรมเมอร์) จะได้รับค่าตอบแทนที่แย่ลง
กราฟิลส์

1
@AriTrachlenberg ทำให้ประเด็นสำคัญแม้ว่าจะมีวิธีมากมายในการประเมินความซับซ้อนของเวลาอัลกอริทึม นิยามสัญกรณ์บิ๊กโอตัวเองบอกใบ้หรือระบุลักษณะทางทฤษฎีของพวกเขาโดยตรงขึ้นอยู่กับผู้เขียน "สถานการณ์กรณีที่เลวร้ายที่สุด" ชัดเจนทำให้ห้องเปิดกว้างสำหรับการคาดเดาและหรือข้อเท็จจริงใหม่ ๆ ในหมู่ผู้ให้ N ในห้องสนทนา ไม่ต้องพูดถึงลักษณะที่แท้จริงของการประมาณเชิงซีมโทติคว่าเป็นสิ่งที่ ... ไม่แน่นอน
Brian Ogden
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.