การแปลรหัสเป็นคณิตศาสตร์
ให้ความหมายในการปฏิบัติการอย่างเป็นทางการ (มากกว่าหรือน้อยกว่า) คุณสามารถแปลรหัส (หลอก) ของอัลกอริทึมได้อย่างแท้จริงในนิพจน์ทางคณิตศาสตร์ที่ให้ผลลัพธ์กับคุณโดยที่คุณสามารถจัดการนิพจน์ให้เป็นรูปแบบที่มีประโยชน์ นี้ทำงานได้ดีสำหรับสารเติมแต่งมาตรการค่าใช้จ่ายเช่นจำนวนของการเปรียบเทียบสัญญาแลกเปลี่ยนงบหน่วยความจำเข้าถึงรอบบางความต้องการของเครื่องที่เป็นนามธรรมและอื่น ๆ
ตัวอย่าง: การเปรียบเทียบใน 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=0n−2∑j=0n−i−21=⋯=n(n−1)2=(n2) ,
โดยที่คือค่าใช้จ่ายสำหรับการดำเนินการแต่ละบรรทัด 5 (ซึ่งเรานับ)1
ตัวอย่าง: Swaps ใน Bubblesort
ฉันจะแสดงโดยโปรแกรมย่อยที่ประกอบด้วยบรรทัดไปและโดยค่าใช้จ่ายสำหรับการดำเนินการโปรแกรมย่อยนี้ (หนึ่งครั้ง)Pi,ji
j
Ci,j
ตอนนี้ขอบอกว่าเราต้องการนับแลกเปลี่ยนที่เป็นวิธีการที่มักจะถูกดำเนินการ นี่คือ "บล็อกพื้นฐาน" ซึ่งเป็นโปรแกรมย่อยที่จะดำเนินการทางอะตอมเสมอและมีค่าใช้จ่ายคงที่ (ที่นี่ ) การทำสัญญาบล็อกดังกล่าวเป็นสิ่งที่มีประโยชน์อย่างหนึ่งที่เรามักใช้โดยไม่ต้องคิดหรือพูดถึงมันP6,81
ด้วยการแปลที่คล้ายกันข้างต้นเรามาถึงสูตรต่อไปนี้:
Cswaps(A)=∑i=0n−2∑j=0n−i−2C5,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))+{10,A(i,j)[j]>A(i,j)[j+1],else{}
สำหรับอาเรย์อินพุตที่กำหนดค่าใช้จ่ายเหล่านี้มีการกำหนดไว้อย่างดี แต่เราต้องการคำแถลงทั่วไปมากขึ้น เราต้องทำให้สมมติฐานที่แข็งแกร่งขึ้น ให้เราตรวจสอบสามกรณีทั่วไป
กรณีที่เลวร้ายที่สุด
เพียงแค่ดูที่ผลรวมและสังเกตว่า , เราสามารถหาขอบเขตบนเล็กน้อยสำหรับค่าใช้จ่าย:C5,9(A(i,j))∈{0,1}
Cswaps(A)≤∑i=0n−2∑j=0n−i−21=n(n−1)2=(n2){2}
แต่สิ่งนี้สามารถเกิดขึ้นได้หรือไม่นั่นคือมีสำหรับขอบเขตบนนี้หรือไม่ ตามที่ปรากฎว่าใช่: ถ้าเราใส่อาเรย์เรียงขององค์ประกอบที่แตกต่างกันแบบคู่กลับกันผกผันทุกการวนซ้ำจะต้องทำการสลับ ดังนั้นเราจึงได้จำนวนบับเบิลพอร์ตที่เลวร้ายที่สุดอย่างแน่นอนA
กรณีที่ดีที่สุด
ตรงกันข้ามมีขอบเขตล่างที่น่ารำคาญ:
Cswaps(A)≥∑i=0n−2∑j=0n−i−20=00
สิ่งนี้สามารถเกิดขึ้นได้: ในอาร์เรย์ที่เรียงลำดับแล้ว Bubblesort จะไม่ทำการสลับครั้งเดียว
กรณีเฉลี่ย
กรณีที่แย่ที่สุดและดีที่สุดเปิดช่องว่างค่อนข้าง แต่จำนวน swaps ทั่วไปคืออะไร? เพื่อที่จะตอบคำถามนี้เราจำเป็นต้องกำหนดความหมาย "ทั่วไป" ในทางทฤษฎีเราไม่มีเหตุผลที่จะชอบสิ่งใดสิ่งหนึ่งเหนือสิ่งอื่นดังนั้นเราจึงมักจะมีการแจกแจงแบบสม่ำเสมอในทุก ๆ ทางที่เป็นไปได้ เรา จำกัด ตัวเองให้อยู่ในอาร์เรย์ด้วยองค์ประกอบที่แตกต่างกันตามลำดับและสมมติว่าเป็นแบบจำลองการเปลี่ยนแปลงแบบสุ่ม
จากนั้นเราสามารถเขียนค่าใช้จ่ายเช่นนี้²:
E[Cswaps]=1n!∑A∑i=0n−2∑j=0n−i−2C5,9(A(i,j))
ตอนนี้เราต้องไปไกลกว่าการจัดการกับผลรวมอย่างง่าย โดยการดูอัลกอริทึมเราทราบว่าการสลับทุกครั้งจะลบการผกผันเดียวใน (เราเพียงแค่สลับneighbours³) นั่นคือจำนวนของสัญญาแลกเปลี่ยนดำเนินการในเป็นว่าจำนวน inversionsของ ดังนั้นเราสามารถแทนที่ผลรวมสองภายในและรับAAinv(A)A
E[Cswaps]=1n!∑Ainv(A)(A)
โชคดีที่เรามีจำนวนผู้รุกรานโดยเฉลี่ยที่พิจารณาแล้วว่าเป็น
E[Cswaps]=12⋅(n2)
ซึ่งเป็นผลสุดท้ายของเรา โปรดทราบว่านี่เป็นครึ่งราคาที่เลวร้ายที่สุด
- โปรดทราบว่าอัลกอริทึมได้รับการกำหนดอย่างรอบคอบเพื่อให้การวนซ้ำ "ครั้งสุดท้าย"
i = n-1
ของลูปด้านนอกที่ไม่เคยทำสิ่งใด ๆ
- " " เป็นสัญลักษณ์ทางคณิตศาสตร์สำหรับ "ค่าที่คาดหวัง" ซึ่งนี่เป็นค่าเฉลี่ยE
- เราเรียนรู้ไปตามวิธีที่ไม่มีอัลกอริทึมที่แลกเปลี่ยนองค์ประกอบใกล้เคียงเท่านั้นที่สามารถ asymptotically เร็วกว่า Bubblesort (แม้โดยเฉลี่ย) - จำนวนการรุกรานนั้นมีขอบเขตต่ำกว่าสำหรับอัลกอริธึมดังกล่าวทั้งหมด นี้นำไปใช้เช่นการแทรกเรียงและการเลือกเรียง
วิธีการทั่วไป
เราได้เห็นในตัวอย่างที่เราต้องแปลโครงสร้างการควบคุมเป็นคณิตศาสตร์ ฉันจะนำเสนอชุดกฎการแปลทั่วไป นอกจากนี้เรายังเห็นว่าค่าใช้จ่ายของโปรแกรมย่อยใด ๆ อาจขึ้นอยู่กับสถานะปัจจุบันนั่นคือ (ประมาณ) มูลค่าปัจจุบันของตัวแปร เนื่องจากอัลกอริทึม (ปกติ) แก้ไขสถานะวิธีการทั่วไปจึงค่อนข้างยุ่งยากที่จะสังเกตเห็น หากคุณเริ่มรู้สึกสับสนฉันขอแนะนำให้คุณกลับไปที่ตัวอย่างหรือทำขึ้นของคุณเอง
เราแสดงสถานะปัจจุบันด้วย (ลองจินตนาการว่ามันเป็นชุดของการกำหนดตัวแปร) เมื่อเรารันโปรแกรมที่เริ่มต้นใน stateเราจะสิ้นสุดใน state ( ถูกยกเลิก)ψP
ψψ/PP
งบส่วนบุคคล
รับเพียงคำเดียวS;
, คุณกำหนดค่าใช้จ่ายปอนด์ต่อตารางนิ้ว) โดยทั่วไปจะเป็นฟังก์ชันคงที่CS(ψ)
การแสดงออก
หากคุณมีการแสดงออกE
ของแบบฟอร์มE1 ∘ E2
(พูดการแสดงออกทางคณิตศาสตร์ที่∘
อาจจะเพิ่มหรือการคูณคุณจะเพิ่มค่าใช้จ่ายซ้ำ:
CE(ψ)=c∘+CE1(ψ)+CE2(ψ)ปอนด์ต่อตารางนิ้ว)
สังเกตได้ว่า
- ค่าใช้จ่ายในการดำเนินงานอาจไม่คงที่ แต่ขึ้นอยู่กับค่าของและและc∘E1E2
- การประเมินผลของนิพจน์อาจเปลี่ยนแปลงสถานะในหลายภาษา
ดังนั้นคุณอาจต้องยืดหยุ่นกับกฎนี้
ลำดับ
เมื่อให้โปรแกรมP
เป็นลำดับของโปรแกรมQ;R
คุณจะต้องเพิ่มค่าใช้จ่าย
CP(ψ)=CQ(ψ)+CR(ψ/Q){Q})
เงื่อนไข
ให้โปรแกรมP
ของแบบฟอร์มif A then Q else R end
ค่าใช้จ่ายขึ้นอยู่กับสถานะ:
CP(ψ)=CA(ψ)+{CQ(ψ/A)CR(ψ/A),A evaluates to true under ψ,else
โดยทั่วไปการประเมินA
อาจเปลี่ยนแปลงสถานะได้ดีดังนั้นการอัพเดทค่าใช้จ่ายของแต่ละสาขา
สำหรับลูป
รับโปรแกรมP
ของแบบฟอร์มfor x = [x1, ..., xk] do Q end
กำหนดค่าใช้จ่าย
CP(ψ)=cinit_for+∑i=1kcstep_for+CQ(ψi∘{x:=xi})
ที่เป็นรัฐก่อนการประมวลผลสำหรับค่าคือหลังจากที่ซ้ำกับที่ถูกตั้งค่าให้, ... ,ψiQ
xi
x
x1
xi-1
สังเกตค่าคงที่พิเศษสำหรับการบำรุงรักษาลูป ต้องสร้างตัวแปรลูป ( ) และกำหนดค่า ( ) สิ่งนี้มีความเกี่ยวข้องตั้งแต่cinit_forcstep_for
- การคำนวณครั้งต่อไป
xi
อาจมีค่าใช้จ่ายสูงและ
- -
for
ลูปที่มีเนื้อความว่างเปล่า (เช่นหลังจากทำให้การตั้งค่าที่ดีที่สุดในกรณีที่ง่ายที่สุดด้วยค่าใช้จ่ายเฉพาะ) ไม่มีค่าใช้จ่ายใด ๆ หากมันทำการวนซ้ำ
ในขณะที่ลูป
รับโปรแกรมP
ของแบบฟอร์มwhile A do Q end
กำหนดค่าใช้จ่าย
CP(ψ) =CA(ψ)+{0CQ(ψ/A)+CP(ψ/A;Q),A evaluates to false under ψ, else
โดยการตรวจสอบอัลกอริทึมการกลับเป็นซ้ำนี้มักจะแสดงได้อย่างดีว่าเป็นผลรวมที่ใกล้เคียงกับลูปสำหรับลูป
ตัวอย่าง:พิจารณาอัลกอริธึมสั้น ๆ นี้:
while x > 0 do 1
i += 1 2
x = x/2 3
end 4
โดยการใช้กฎเราจะได้รับ
C1,4({i:=i0;x:=x0}) =c<+{0c+=+c/+C1,4({i:=i0+1;x:=⌊x0/2⌋}),x0≤0, else
ด้วยค่าใช้จ่ายคงที่บางรายการสำหรับแต่ละข้อความสั่ง เราถือว่าโดยปริยายว่าสิ่งเหล่านี้ไม่ได้ขึ้นอยู่กับสถานะ (ค่าของและ); สิ่งนี้อาจจะใช่หรือไม่ใช่จริงใน "ความจริง": คิดว่าล้น!c…i
x
ตอนนี้เราต้องแก้ปัญหาการเกิดซ้ำนี้{1,4} เราทราบว่าจำนวนการทำซ้ำไม่ใช่ค่าใช้จ่ายของลูปบอดี้นั้นขึ้นอยู่กับค่าของดังนั้นเราจึงสามารถวางได้ เราถูกทิ้งให้อยู่กับการเกิดซ้ำนี้:C1,4i
C1,4(x)={c>c>+c+=+c/+C1,4(⌊x/2⌋),x≤0, 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})C4({n:=n0}),n0≤1, else=c≤+{creturncreturn+c∗+ccall+Cfac({n:=n0−1}),n0≤1, else
โปรดทราบว่าเราไม่สนใจสถานะโลกเนื่องจากfac
เห็นได้ชัดว่าไม่สามารถเข้าถึงได้ การเกิดซ้ำโดยเฉพาะนี้ง่ายต่อการแก้ไข
Cfac(ψ)=ψ(n)⋅(c≤+creturn)+(ψ(n)−1)⋅(c∗+ccall)
เราได้ครอบคลุมคุณสมบัติภาษาที่คุณจะพบในรหัสหลอกทั่วไป ระวังค่าใช้จ่ายแอบแฝงเมื่อวิเคราะห์โค้ดหลอกระดับสูง หากมีข้อสงสัยคลี่ออก สัญกรณ์อาจดูยุ่งยากและแน่นอนว่าเป็นเรื่องของรสนิยม แม้ว่าแนวคิดที่ระบุไว้จะไม่สามารถเพิกเฉยได้ อย่างไรก็ตามด้วยประสบการณ์บางอย่างคุณจะสามารถเห็นได้ทันทีว่าส่วนใดของรัฐที่เกี่ยวข้องกับการวัดค่าใช้จ่ายตัวอย่างเช่น "ขนาดปัญหา" หรือ "จำนวนจุดยอด" ส่วนที่เหลือสามารถทิ้งได้ - สิ่งนี้ทำให้สิ่งต่าง ๆ ง่ายขึ้นอย่างมาก!
หากคุณคิดว่าตอนนี้มันซับซ้อนเกินกว่าจะได้รับคำแนะนำ: มันคือ ! การได้รับต้นทุนที่แน่นอนของอัลกอริทึมในแบบจำลองใด ๆ ที่อยู่ใกล้กับเครื่องจักรจริงเพื่อเปิดใช้งานการคาดการณ์แบบรันไทม์ และนั่นไม่ได้พิจารณาถึงการแคชและผลกระทบที่น่ารังเกียจอื่น ๆ ในเครื่องจริง
ดังนั้นการวิเคราะห์อัลกอริธึมจึงง่ายขึ้นจนถึงจุดที่สามารถใช้วิธีทางคณิตศาสตร์ได้ ตัวอย่างเช่นหากคุณไม่ต้องการค่าใช้จ่ายที่แน่นอนคุณสามารถประเมินค่าสูงหรือต่ำเกินไปได้ทุกจุด (สำหรับผู้ที่มีภาระน้อยกว่า): ลดกลุ่มค่าคงที่, กำจัดเงื่อนไข, ลดความซับซ้อนของผลรวมและอื่น ๆ
หมายเหตุเกี่ยวกับค่าใช้จ่ายที่เชิงเส้นกำกับ
สิ่งที่คุณมักจะพบในวรรณกรรมและบนเว็บคือ "การวิเคราะห์ Big-Oh" คำที่เหมาะสมคือการวิเคราะห์เชิงเส้นกำกับซึ่งหมายความว่าแทนที่จะทำให้ได้ค่าใช้จ่ายที่แน่นอนตามที่เราทำในตัวอย่างคุณเพียงแค่ให้ค่าใช้จ่ายถึงปัจจัยคงที่และในขีด จำกัด (พูดโดยประมาณ "สำหรับใหญ่")n
นี่คือ (มัก) ยุติธรรมเนื่องจากงบนามธรรมมีบางส่วนค่าใช้จ่าย (ไม่ทราบโดยทั่วไป) ในความเป็นจริงขึ้นอยู่กับเครื่องระบบปฏิบัติการและปัจจัยอื่น ๆ และเวลาการทำงานสั้นอาจถูกครอบงำโดยระบบปฏิบัติการการตั้งค่าขั้นตอนในสถานที่แรกและ whatnot ดังนั้นคุณจะได้รับการรบกวนบ้าง
นี่คือวิธีการวิเคราะห์เชิงความสัมพันธ์กับวิธีการนี้
ระบุการดำเนินการที่โดดเด่น (ที่ชักจูงต้นทุน) นั่นคือการดำเนินการที่เกิดขึ้นบ่อยที่สุด (สูงถึงปัจจัยคงที่) ในตัวอย่างของ Bubblesort หนึ่งทางเลือกที่เป็นไปได้คือการเปรียบเทียบในบรรทัดที่ 5
อีกทางเลือกหนึ่งคือผูกค่าคงที่ทั้งหมดไว้สำหรับการดำเนินการเบื้องต้นด้วยการตอบสนองสูงสุด (จากด้านบน) ขั้นต่ำของพวกเขา (จากด้านล่าง) และดำเนินการวิเคราะห์ตามปกติ
- ทำการวิเคราะห์โดยใช้จำนวนการดำเนินการของการดำเนินการนี้เป็นต้นทุน
- เมื่อลดความซับซ้อนให้ประมาณการ ใช้ความระมัดระวังเพื่อให้การประมาณการจากด้านบนหากเป้าหมายของคุณเป็นขอบเขตสูงสุด ( ) resp จากด้านล่างหากคุณต้องการลดขอบเขต ( )OΩ
ให้แน่ใจว่าคุณเข้าใจความหมายของสัญลักษณ์กุ๊บ โปรดจำไว้ว่าขอบเขตดังกล่าวอยู่สำหรับทั้งสามกรณี ; การใช้ไม่ได้แปลว่าเป็นกรณีที่เลวร้ายที่สุดO
อ่านเพิ่มเติม
มีความท้าทายและลูกเล่นเพิ่มเติมในการวิเคราะห์อัลกอริทึม นี่คือคำแนะนำในการอ่าน
มีคำถามมากมายที่ติดแท็กการวิเคราะห์อัลกอริทึมโดยใช้เทคนิคที่คล้ายกับสิ่งนี้