Complexity Lecturers : Boontee Kruatrachue Room no. 913 Kritawan Siriboon Room no. 913 Text : Data Structures & Algorithm Analysis in C, C++,… Mark Allen Weiss, Addison Wesley
ความซับซ้อนของอัลกอริธึม Algorithmic Complexity int fac (int n) { if (n <= 1) //base case return 1; else { int x; x = fac(n-1); //recursive return n * x; } fac(4) fac(3) fac(2) fac(1) Stack 4*6 = 24 fac(4); 1 2 3 4 6 n x 1 2*1 = 2 3*2 = 6 Algorithm Bad ? Good ? Excellent ? รันเสร็จเร็ว ใช้ memory น้อย ความซับซ้อน / Complexity Space complexity จำนวน memory ที่ต้องใช้ให้รันเสร็จ Time complexity จำนวน CPU time ที่ต้องใช้ให้รันเสร็จ Worst case Average case Best Case ประสิทธิภาพ / efficiency ซับซ้อน มาก → รันช้า - ใช้ space มาก → ประสิทธิภาพ ต่ำ ซับซ้อน น้อย → รันเร็ว - ใช้ space น้อย → ประสิทธิภาพ สูง Performance Analysis ประมาณค่า complexity ล่วงหน้า Performance Measurement วัด space & time ในการรันครั้งนั้น
Time of Algorithm CPU speed Instruction set Disk speed Compiler Algorithm เดียวกัน เร็ว-ช้า ต่างกันได้ จากปัจจัยอื่น ต้องการ วัดเวลาของตัว algorithm เอง โดยไม่นำสิ่งเหล่านี้มาเป็นประเด็น
Examples of Time Function T(n) Algorithm 1 Algorithm 2 Algorithm 3 for i=1 to n do a = 1; b = 2; c = 3; c = 3; d = 4; for j=1 to n do a = 1; ถ้า แต่ละ assignment ใช้เวลาคงที่ 1 หน่วย T1(n) = ? 3n T2(n) = ? 4n T3(n) = ? n2 ถ้า T1(n), T2(n) ,T3(n) ทำงานอย่างเดียวกัน จะเลือกใช้ algorithm ใด ? เลือกอย่างไร ? เปรียบเทียบ เทียบเวลาในการรัน เทียบอย่างไร ? Plot Graph ?
Comparing Growth Rate of T(n) time เป็นบวกเสมอ Algorithm ไหน เร็ว-ช้ากว่า? g(n) = n2 บอกไม่ได้ ขึ้นกับค่า n แต่ละจุด ถ้าให้เลือก 4n ? n2 ? 4n growth rate อัตราการเติบโต Why ? n 4n n2 1 4 2 8 3 12 9 16 5 20 25 6 24 36 7 28 49 4n โตไม่เร็ว(<=) กว่า n2 n0 = 4 ช่วงต้นๆ n<4 แม้ว่า แต่ เมื่อ n>=4 และมากขึ้น ๆ 4n เร็วกว่า n2 f(n) = 4n 4n รันนาน เสร็จช้ากว่า n2 input size n เป็นบวกเสมอ นั่นคือ ดูไปจนถึง n ย่างสู่ค่าใดค่าหนึ่ง หรือ n → ∞ ต่อไปนี้ เราจะไม่เทียบที่ n ค่าใดค่าหนึ่ง เราดู Growth Rate อัตราการเติบโต แทน
สนใจ n ใหญ่ ตั้งแต่ค่าค่าหนึ่ง n0 เป็นต้นไปถึงค่า ∞ n ≥ n0 , n → ∞ Asymptotic Analysis Asymptotic Analysis : คือ การวิเคราะห์ค่า T(n) เมื่อ n ย่างสู่ค่าใดค่าหนึ่ง(ใหญ่) หรือ n → ∞ time เป็นบวกเสมอ ดู growth rate T(n) g(n) = n2 f(n) = 4n ∞ input size เป็นบวกเสมอ n0 สนใจ n ใหญ่ ตั้งแต่ค่าค่าหนึ่ง n0 เป็นต้นไปถึงค่า ∞ n ≥ n0 , n → ∞
Classes of Algorithms บางทีเรามี algorithm หลายอันที่ทำงานเดียวกัน เช่น Sorting Algorithms เราอยากแบ่งกลุ่ม algorithm ตาม Growth Rate นิยมประมาณเข้ากับฟังก์ชั่นมาตรฐานง่ายๆ Linear Growth Rate : กลุ่ม n 4 n 7n + 1 100 n Quadratic Growth Rate : กลุ่ม n2 107 n2 + 5 n2 n2 - 75 Cubic Growth Rate : กลุ่ม n3 n3 + 5 n3 n3 - 7 แม้ runtime จะต่างกัน เช่น 4n กับ 7n + 1 , 107 n2 + 5 กับ n2 - 75 แต่เมื่อ n มากๆ (Asymtoticaltic Analysis ) แทบไม่มีความหมาย มันอยู่กลุ่มเดียวกัน
Comparing T(n) to Big O T6(n) = n log3 n – ¾ log n T2 (n) = ⅞n! + ⅝n9 log n T7(n) = ½log2 n T1(n) = 86 n9log8 n + ⅞ n3 + ⅚ nn T3(n) = √n + n + 2n T4(n) = ⅜n3 log8 n – ¾ log n T5(n) = n2 - ½ T8(n) = 5√n + ⅞ ถ้าT(n) ซับซ้อนมาก ? g(n) = nn ? input size time อันไหนดี ? g(n) = n! ? T(n) ซับซ้อน ทำให้ ไม่ซับซ้อน ไม่ได้ แต่เปรียบเทียบT(n) กับ g(n) ที่เลือกให้ดูง่ายกว่าได้ ทำให้มองเห็น T(n) ได้ชัดเจนขึ้นว่าเป็นประมาณเท่าใด อยากรู้ว่ารันช้า (ใช้ time ) มากแค่ไหน -> เลือก g(n) ที่ใช้เวลามากกว่าT(n) เรียกว่า g(n) เป็น upper bound หรือบาวข้างบนT(n) g(n) = 2n ? g(n) = n3 ? g(n) = n2 ? g(n) = n log n ? g(n) = √n ? g(n) = log n ? จะเห็นว่ามี g(n) หลายตัว ที่ใช้เวลามากกว่าT(n) g(n) ทั้งหมดนี้เป็น upper bound บน T(n) เลือก g(n) ตัวไหน? ที่จะแสดงให้เห็น T(n) ได้ดีที่สุด ? เลือก g(n) ตัวที่ใกล้ (tight) กับ T(n) มากที่สุด ทำให้เห็น T(n) ในรูป g(n) ที่ง่ายกว่า T(n) T(n) = 5√n + ⅞
Tight Upper Bound วาวา พลอย ใหม่ ญาญ่า
Comparing T(n) to Big O T(n) is O(g(n)) g(n) = nn ? input size time T(n) is O(g(n)) เขียนโดยใช้ Big O Notation อ่านว่า g(n) เป็น Big O ของ T(n) T(n) มี Big O เป็น g(n) แปลว่า g(n) bound ข้างบน T(n) T(n) ถูก bound ข้างบน โดย g(n) (แบบ asymtotic – กล่าวภายหลัง) g(n) = n! ? g(n) = 2n ? g(n) = n3 ? g(n) = n2 ? g(n) = n log n ? g(n) = √n ? g(n) = log n ? T(n) = 5√n + ⅞ g(n) ทั้งหมดนี้เป็น Big O ของ T(n)
√n = g(n) < T(n) = 5√n + ⅞ Asymtotically Bound T(n) is O(g(n)) g(n) ทั้งหมดนี้เป็น Big O ของT(n) g(n) = nn ? input size time g(n) = √n T(n) = 5√n + ⅞ T(n) , g(n) อะไรมากกว่ากัน ? g(n) = n! ? √n = g(n) < T(n) = 5√n + ⅞ ทำไมพูดว่า g(n) บาวข้างบน T(n) ? g(n) = 2n ? g(n) = n3 ? g(n) = n2 ? g(n) = n log n ? g(n) = √n ? g(n) = log n ? Asymtotic = เมื่อ n → ∞ หรือ n →ค่ามากๆ g(n) bound above T(n) แบบ Asymtotic T(n) = 5√n + ⅞ g(n) = √n ? พอๆ กัน เมื่อ n → ∞ , terms 5 & ⅞ ไม่มีความหมาย ! Big Oh Notation ทิ้งตัวคูณ constant, ทิ้ง term ที่เล็กกว่า และ ไม่สนใจ n เล็ก T(n) = 5√n + ⅞ ดังนั้น สำหรับขนาด data ที่อาจเป็นไปได้ อาจไม่ได้ algorithm ที่เร็วที่สุด แต่ ใช้เปรียบเทียบ algorithm ได้ดี เมื่อ n มีขนาดใหญ่ g(n) ทั้งหมดนี้เป็น Big O ของ T(n)
Asymptotically bound, c * g(n), n ≥ n0 Big O Notation ใช้เปรียบเทียบกับฟังก์ชั่น T(n) ของอัลกอริธึม กับ ฟังก์ชั่น g(n) ของ Big O ที่เราเลือกมาใช้เปรียบเทียบ เมื่อหาค่าคงที่ C มาคูณ g(n) ของ Big O เป็น c*g(n) แล้ว c*g(n) ≥ T(n) เสมอ ตั้งแต่ n ≥ n0 c*g(n) เรียก g(n) bound อยู่ข้างบน T(n) แบบ asymtotic asymtitic T(n) เลือก g(n) ใกล้ (tight) พอช่วยบีบให้เห็น limit ของT(n) g(n) n0 ∞ นิยมเลือก g(n) เป็นรูปมาตรฐานง่าย ๆ 1, c Constant log n Logarithmic Log2n Log-squared n Linear n log n Log-linear n1.5 n2 Quadratic n3 Cubic nk Polynomial xn Exponential Big แปลว่า capital O แปลว่า order Big O = order of complexity = ลำดับของความซับซ้อน Big O ที่ใกล้พอ จะช่วยแบ่งประเภท T(n) ได้ กลุ่มเดียวกันแทนด้วย Big O เดียวกัน ช่วยจัดอันดับ(order) ความซับซ้อนของ T(n) Big O นำมาใช้ประเมินการใช้งานของ resoures ต่าง ๆ ของอัลกอริธึม
Comparision in O(n) n 4n ½n อันไหนใช้ time มาก? เป็นบวกเสมอ 4n n ½n อันไหนใช้ time มาก? มอง n ไปไกลๆ แค่ไหน 4n ก็มากกว่า input size เป็นบวกเสมอ 4n มากกว่า n ตั้ง 4 เท่า พูดว่าไม่มีผลได้อย่างไร ทำไมทั้ง 3 อยู่ในกลุ่ม simplified form n เดียวกัน ลองเทียบกับกลุ่ม n2 ที่มี constant น้อยมาก ๆคูณ
Compare O(n) – O(n2) เห็นได้ชัดว่า n และ n2 เป็นคนละกลุ่มกัน ลองเทียบกับกลุ่ม n2 ที่มี constant น้อยมาก ๆ คูณ ต่อเส้น n ไปไกล ๆ เปรียบเทียบกับ 4 n .0001 n2 และ .0003 n2 จะตัด 4 n ? ยังไง .0003 n2 และ .0001 n2 ก็จะตัด กลุ่ม n ทั้ง 3 เส้น .0003n2 .0001n2 4n n 4n ½ n 4 n จะมากแค่ไหน ก็แพ้ .0003 n2 .0001 n2 อยู่ดี แม้ว่า constant .0001 .0003 < 4 มาก .0003 n2 .0001 n2 เห็นได้ชัดว่า n และ n2 เป็นคนละกลุ่มกัน
Compare O(n) – O(n2) – O(n3) ลองแข่ง n2 กับ 4n2+n+3 ซึ่งมีทั้ง 4 คูณ + term n เพิ่ม แถม + 3 อีก n มีความหมายมากกว่า 3 แต่ก็ยังไม่มีความหมาย เมื่อเปรียบเทียบกับ n3 เห็นได้ชัดว่า n n2 และ n3 เป็นคนละกลุ่มกัน 4n2+n+3 n3 n2 4n
Same Class O(n2) n2 4n2+n+3 5n2 n3 c n2 ≥ 4n2+n+3 ทำอย่างไรจะให้ กับ อยู่ในกลุ่มเดียวกัน ? 4n2+n+3 n2 5n2 ≥ 4n2+n+3 ,c = 5 หาค่าคงบวกที่ c มาคูณ n2 เป็น c n2 จะได้แข่งกับ 4n2+n+3 ได้ 4n2 + n2 ≥ 4n2+n+3 หา c ที่ทำให้ cn2 ตัด 4n2+n+3 ที่ n0 จุดหนึ่ง และจาก n0 ไป cn2 ≥ 4n2+n+3 เสมอ n2 ≥ n+3 ณ n0 = 3 5n2 ≥ 4n2+n+3 , when n≥3 เรียก n2 เป็น Asymtotic Upper Bound บน 4n2+n+3 n2 4n2+n+3 5n2 n3 ในทางกลับกัน 4n2+n+3 ต้องแข่งกับได้ n2 จึงจะอยู่กลุ่มเดียวกัน หาค่าคงบวกที่ c มาคูณ เป็น c(4n2+n+3) จะได้แข่งกับ n2 ได้ หา c มาคูณทำให้ c(4n2+n+3) ตัด n2 ที่ n0 จุดหนึ่ง และจาก n0 ไป c(4n2+n+3) ≥ n2 เสมอ เรียก 4n2+n+3 เป็น Asymtotic Upper Bound บน n2 c (4n2+n+3) ≥ n2 c = 1, n0 = 1 4n2+n+3 ≥ n2, when n≥3 n0=3 ∞ เมื่อทั้งคู่ต่าง Asymtotic Upper Bound กัน มันอยู๋ในลำดับเดียวกัน โตเร็วพอๆกัน
Steps for T(n) = O(g(n) เมื่อได้ ฟังก์ชั่นของอัลกอริธึมเป็นฟังก์ชั่นของขนาด input n เช่น T(n) = 3n2 + 4n +7 หาฟังก์ชั่นที่จะมาเป็น Big Oh ของ T(n) โดยดูที่ growth rate ที่สูงกว่าแต่ใกล้กัน ให้อยู่ในรูปง่าย ๆ เช่น log n, n, n2, n3 n2 หรือ n3 ก็เป็น Big Oh ของ 3n2 + 4n +7 ได้ แต่ n2 ดีกว่า เพราะใกล้กันมากกว่า การเปรียบเทียบ T(n) กับ Big Oh จะเทียบ ตั้งแต่ n ผ่านค่าค่าหนึ่งไปจนถึง ∞ จึงเป็นการมอง อัตราการเติบโต (growth rate) ไม่ได้มองที่ค่า n ค่าใดค่าหนึ่ง Big Oh จะ (asymptotic) bound อยู่ข้างบน T(n) T(n) จะโตไม่เร็วกว่า Big Oh ของมัน n2 asymptotic bound อยู่ข้างบน 3n2 + 4n +7 3n2 + 4n +7 จะโตไม่เร็วกว่า n2 Big Oh ช่วยจัดอันดับให้ T(n) ให้อยู่ในรูปที่ง่ายขึ้น เมื่อมี algorithm หลายๆอันที่ทำงานเดียวกัน เราสามารถเลือก algorithm ที่มีลำดับที่ดีกว่าได้โดยดูจาก Big Oh
f(n) โตไม่เร็วกว่า g(n) Definition of Big O big Oh f(n) = O (g(n)) if there are positive constants c and n0 such that f(n) ≤ c * g(n) when n ≥ n0 big Oh สำหรับ f(n) และ g(n) พูดว่า f(n) มีบิกโอเป็น g(n) f(n) = O (g(n)) เมื่อมี constants บวก c และ n0 ซึ่งทำให้ เมื่อ n มีค่าตั้งแต่ n0 เป็นต้นไป (n ≥ n0 ) f(n) ≤ c * g(n) เสมอ เรียกว่า g(n) asymtotically bound ข้างบน f(n) f(n) โตไม่เร็วกว่า g(n) f(n) = O(g(n)) time *g(n) 2 g(n) f(n) ≤ c * g(n) f(n) n0 input size n ≥ n0
Proof of Big O 3 1 3 *n n n ≥ 1 n asymtotically bound ข้างบน 2n+1 2n+1 ถูก asymtotically upper bound โดย n n asymtotically bound ข้างบน 2n+1 2n+1 โตไม่เร็วกว่า n จะ Pf ว่า 2n+1 มีบิกโอเป็น n 2n+1 = O(n) 2n+1 = O(n) input size time 2n+1 n 2n+1 ≤ c * n เมื่อ n ≥ n0 ต้องหา constants บวก c และ n0 ซึ่งทำให้ 3 1 3 *n 3n = 2n + n 3 2n+1 ≤ 3 * n when n ≥ 1 2n ≤ 2n และ 1 ≤ n , n ≥ 1 ∴ 2n+1 ≤ 3 * n , n ≥ 1 2n+1 = O (n) ∵ มี c = 3, n0 = 1 ทำให้ 1 n ≥ 1 2n+1 ≤ 3 * n when n ≥ 1 2n+1 มีบิกโอเป็น n 2n+1 = O(n) เพราะมี constants บวก c=3 และ n0 =1 ซึ่งทำให้ 2n+1 ≤ 3 * n , n ≥ 1
Proof of Big O (cont.) 3 *n2 n2 n ≥ 1 n2 asymtotically bound ข้างบน 2n+1 2n+1 ถูก asymtotically upper bound โดย n2 จะ Pf ว่า 2n+1 มีบิกโอเป็น n2 2n+1 = O(n2) 2n+1 = O(n2) input size time 2n+1 n2 2n+1 ≤ 3 * n2 when n ≥ 1 2n+1 ≤ c * n2 เมื่อ n ≥ n0 ต้องหา constants บวก c และ n0 ซึ่งทำให้ 3 *n2 3 3 1 3n2 = 2n2 + n2 2n+1 โตไม่เร็วกว่า n2 2n ≤ 2n2 และ 1 ≤ n2 , n ≥ 1 ∴ 2n+1 ≤ 3 * n2 , n ≥ 1 1 n ≥ 1 2n+1 มีบิกโอเป็น n2 2n+1 = O(n2) เพราะมี constants บวก c=3 และ n0 =1 ซึ่งทำให้ 2n+1 ≤ 3 * n2 , n ≥ 1
Proof of Big O (cont.) * n 1 1 big Oh f(n) = O (g(n)) if there are positive constants c and n0 such that f(n) ≤ c * g(n) when n ≥ n0 n asymtotically bound ข้างบน log2n log2n ถูก asymtotically upper bound โดย n log2n = O(n) time input size n log2n * n 1 log2n โตไม่เร็วกว่า n log2n ≤ 1 * n when n ≥ 1 จะ Pf ว่า log2n มีบิกโอเป็น n log2n = O (n) ต้องหา constants บวก c และ n0 ซึ่งทำให้ log2n ≤ c * n เมื่อ n ≥ n0 1 n ≥ 1 1 log2n ≤ n , n ≥ 1
Proof of Big O (cont.) 4 n ≥ 10 n2 asymtotically bound ข้างบน 3n2+10 จะ Pf 3n2+10 is O(n2) n2 asymtotically bound ข้างบน 3n2+10 ต้องหา constants บวก c และ n0 ซึ่งทำให้ 3n2+10 ≤ c * n2 เมื่อ n ≥ n0 3n2+10 ถูก asymtotically upper bound โดย n2 3n2+10 โตไม่เร็วกว่า n2 4 3n2+10 = O(n2) 10 4n2 = 3n2 + n2 3n2 ≤ 3n2 และ 10 ≤ n2 , n ≥ 10 time input size ∴ 3n2 +10 ≤ 4 * n2 , n ≥ 10 3n2+10 ≤ 4*n2 when n ≥ 10 * n2 4 3n2+10 n2 n ≥ 10
Proof of Big O (cont.) ในการพิสูจน์ Big Oh โดยหาค่า constants บวก c และ n0 มีได้หลายคู่ เลือกคู่ใดก็ได้ แต่ หาก Big Oh g(n) ไม่เป็น asymtotical upper bound ของ f(n) จะหา constants บวก c และ n0 ไม่ได้เลยที่ทำให้ f(n) ≤ c * g(n) เมื่อ (n ≥ n0 ) n2 is not O(n) เพราะ ไม่มี constants บวก c และ n0 ซึ่งทำให้ n2 ≤ c * n ( เมื่อ n ≥ n0 ) ดังนั้น n2 ≠ O(n)
Least (Tight) Upper Bound My child was very nauty. How ? So complicate to explain. T(n) = 87n39 + 6n1.5 – n log n + log2 n - 7 Can you compare ? Too far big Oh. Not that high. To more simple form. That is very close. Still high. Nah. Look narmal for me !
Least (Tight) Upper Bound Choose the tight upper bound ! 2n+1 = O(n) 2n+1 = O(n) 2n+1 = O(n log n) 2n+1 = O(n2) 2n+1 = O(n3) 2n+1 = O(xn)
Big O Notation คิดโดย Edmund Landau และ Paul Bachmann เพื่อใช้ในคณิตศาสตร์บริสุทธิ์ เริ่มพบโดยนักจำนวนชาวเยอรมัน แผยแพร่ ปี 1894 Paul Gustav Heinrich Bachmann (22 June 1837 – 31 March 1920) ได้รับความนิยมและขยายผล โดยนักจำนวนชาวเยอรมัน Edmund Georg Hermann Landau (14 February 1877 – 19 February 1938) Big Oh notation จึงเรียกหลายแบบ Big-O notation Big Oh notation Landau notation Bachmann–Landau notation Asymptotic notation Big Omicron (ตัว o ภาษากรีก) notation
Classification of Algorithms ใช้ Big Oh แบ่งประเภท algorithm ตาม growth rate ของT(n) นิยมใช้รูปฟังก์ชั่นมาตรฐานง่ายๆ 1, c Constant log n Logarithmic log2 n Log-squared n Linear n log n Log-linear n1.5 n2 Quadratic n3 Cubic nk Polynomial xn Exponential logxn = logxy * logyn (logxy เป็น constant) จึงไม่นิยมเขียนฐาน log T(n) ที่มี growth rate เดียวกัน สามารถแทนได้ด้วย Big-O notation เดียวกัน
Classification of Algorithms
Classification of Algorithms
Equals Sign การเขียน f(n) is O(g(n)) หรือ f(n) = O(g(n)) เครื่องหมาย = อาจทำให้เข้าใจผิดได้ เพราะ = มีคุณสมบัติ symmetry O(n) = O(n2) แต่ O(n2) = O(n) ไม่จริง จึงมีความคิดที่จะใช้สัญลักษณ์ของ set f(n) ∈ O(g(n))โดยคิดว่า O(g(n)) เป็น class ของฟังก์ชั่น h(n) ซึ่ง |h(n)| ≤ C|g(n)| สำหรับ constant c นิยมใช้ = ในความหมาย is Knuth : เป็น one-way equalities ฉันเป็นคน แต่ไม่ใช่ คนเป็นฉัน
O(1) Constant Order Constant time runtime คงที่ ไม่ขึ้นกับ input size n Examples: a[i] push(), pop() fix size stack int sum(int n){ sum = 0; for( int i=1 ; i<=n; i++) sum = sum + i; return sum; } int i=1
O(n) Linear Order (Linear Search) Linear time runtime โตเป็น linear กับ n ที่เพิ่ม Linear Search Search หา x จาก array หรือ linear linked list size n How many probes ? = x ? 1 2 3 n = x ? = x ? = x ? = x ? = x ? = x ? probes = n times int search(int x , int a[], int n) { int i = 0; while((i<n) && a[i]!=x){ i++; if(i!=n) return i; return -1; } 1 2 3 4 5 6 3 1 3 1 2n+1 max n+1, max n Loop : *จำนวนครั้งของลูป 1*n=n = 3n+7 = O(n) int i = search(5, a, n); Consecutive statements คิดที่ทำมากที่สุด n > constant 7
O(n2) Quadratic Order O(n) O(n) O(n2) O(n) Quadratic time runtime โตเป็น square กับ n ที่เพิ่ม เช่น bubble sort, selection sort, insertion sort int n = 3; int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; for(int i = 0; i<n; i++){ for(int j = 0; j<n; j++) printf("%d ",a[i][j]); printf("\n"); } O(n) O(n) O(n2) O(n)
O(n3) Cubic Order int maxSubSum1(int a[], int N){ int maxSum = 0; for(int i=0; i<N; i++) for(int j=i; j<N; j++){ int thisSum = 0; for(int k=i; k<=j; k++) thisSum += a[k]; if(thisSum > maxSum) maxSum = thisSum; } return maxSum; อะไรทำมากที่สุด ? 1 2 3 4 5 loop size N loop size N-i (worst case N) loop size j-i+1 (worst case N) line 5 * n*n*n = O(N3)
O(n3) Cubic Order = O(N3) ถ้า k = j - i + 1 j=i → k=1 , j=N-1 →k=N-1 int maxSubSum1(int a[], int N){ int maxSum = 0; for(int i=0; i<N; i++) for(int j=i; j<N; j++){ int thisSum = 0; for(int k=i; k<=j; k++) thisSum += a[k]; if(thisSum > maxSum) maxSum = thisSum; } return maxSum; = O(N3) ถ้า k = j - i + 1 j=i → k=1 , j=N-1 →k=N-1 ถ้า i = ii - 1 i = 0→ii = 1 , i = N-1→ ii = N N – i + 1 → N – ii + 2, N - i → N – ii + 1 เปลี่ยน i → ii
O(log n) Logarithmic Order Logarithmic time runtime โตเป็น log กับ n ที่เพิ่ม int log_2(int n) { //n>=1 int times = 0; for (int i = n; i >= 2; i = i / 2) { times++; } return times; อะไรทำมากที่สุด ? loop ทำ loop กี่ครั้ง ? O(1) เริ่ม ? จบ ? i = n i = 1 ทุกครั้ง size ลดลง ½ ครั้งที่ เหลือ size 1 n/2 n/21 2 n/4 n/22 3 n/8 n/23 ... d n/2d 1 = n /2d 2d = n d = log2n O(log n) logxn = logxy * logyn (logxy เป็น constant) จึงไม่นิยมเขียนฐาน log
O(log n) Logarithmic Order Algorithm = O(log N) ถ้าใช้เวลาคงที่ O(1) ในการลดขนาดของปัญหาลงเป็นอัตราส่วน (โดยมาก ½) แต่ Algorithm = O(N) ถ้าใช้เวลาคงที่แล้วลดขนาดลงของปัญหาลงได้จำนวนคงที่ (เช่นลดลง 1) // O(log n) long pow( long x, int n ){ if( n == 0 ) return 1; if( n == 1 ) return x; if( n%2==0 ) //is even return pow(x*x, n/2); else return pow(x*x, n/2)*x; } // O(n) long fac(int n){ if (n<=1) return 1; else return n * fact(n-1); }
O(log n) Euclid’s Algorithm long gcd( long m, long n ){ while( n != 0 ){ long rem = m % n; m = n; n = rem; } return m; gcd(1989, 1590) M1= 1,989 N1= 1,590 M1 % N1= 399 M2 = 1,590 N2 = 399 M2 % N2 = 393 M3 = 399 N3 = 393 M3 % N3 = 6 M4 = 393 N4 = 6 M4 % N4 = 3 M5 = 6 N5 = 3 M5 % N5 = 0 M6 = 3 = gcd N6 = 0 แม้จะไม่ได้ใช้เวลาคงที่ O(1) ในการลดขนาดของปัญหา แต่สามารถพิสูจน์ได้ว่า จำนวนรอบมากที่สุด = O(log N) If M > N then (M mod N) < M/2 Case 1: if N ≤ M/2 → (M mod N) < N ≤ M/2 เช่น M = 10 , N = 4 ∴ 10 % 4 < N < M/2 Case 2: if N > M/2 → (M mod N) < M-N < M/2 เช่น M = 10 , N = 6 ∴ 10 % 6 < 10-6 < M/2
O(n) Simple Recursive Recursive Function : หลายกรณี recursion ทำแค่ for loop วิเคราะห์เหมือน for loop → O(n) // O(n) long fac(int n){ if (n<=1) return 1; else return n * fact(n-1); } long fib(int n) { if (n<=1) return n; else return fib(n-1) + fib(n-2); } เป็นอีกกรณีหนึ่ง →
Mathematical Induction การพิสูจน์โดย Mathametical Induction ต้องพิสูจน์ 2 กรณี base case พิสูจน์ว่ากรณี n ตั้งต้นน้อยๆ เป็นจริง เช่น n = 0, 1 induction case (Hypothesis case) พิสูจน์ว่า ถ้าที่ n <= x ใดๆ เป็นจริงแล้ว หากพิสูจน์ได้ว่าที่ n = x +1 เป็นจริง ดังนั้นสิ่งที่ต้องการพิสูจน์จะเป็นจริงทุก n ใดๆ Pf n2 ≥ n when n ≥ 0 base case พิสูจน์ว่ากรณี n ตั้งต้นน้อยๆ เป็นจริง เช่น n = 0, 1 when n = 0 : 0 = n2 ≥ n = 0 true when n = 1 : 1 = n2 ≥ n = 1 true ทำอย่างไร จะพิสูจน์ค่าอื่นๆได้ ไม่สามารถพิสูจน์ n ได้ทุกค่า จึงพิสูจน์โดยใช้ induction case (Hypothesis case) แทน นั่นคือ ถ้าหาก ณ n <= x ใดๆ เป็นจริงแล้ว หากพิสูจน์ได้ว่าที่ n = x +1 เป็นจริง ดังนั้นสิ่งที่ต้องการพิสูจน์จะเป็นจริงทุก n ใดๆ n.<=x true n.=x+1 n.=0,n=1 small n = true n.<=x true n.=x+1 if true base case Hypothesis (Induction) case
O(cn) Exponential Order long fib(int n) { if (n<=1) return n; else return fib(n-1)+fib(n-2); } 12 3 ให้ run time เมื่อเรียก fib(n) = T(n) และค่า fib n แทนด้วย fib[n] จะ Pf. ว่า T(n) fib[n] นั่นคือ T(n) = O(xn) โตเป็น exponential T(0) = T(1) = 1 ( จาก code) T(n) = T(n-1) + T(n-2) + c when n2 ( จาก code) pf. base case: ว่า T(n) fib[n] เมื่อ n=0, n=1 Pf. 1=T(0) fib[0]=0, 1=T(1) fib[1]=1 ( จาก A) pf. induction case: ถ้าให้ T(n) fib[n], T(n-1) fib[n-1] เป็นจริง จะต้องพิสูจน์ว่า T(n+1) fib[n+1] เป็นจริง 1. T(n+1) = T(n) + T(n-1) + c ( จาก B) 2. fib[n+1] = fib[n] + fib[n-1] ( จากกฏของ fib ) T(n+1) fib[n+1] จริง เพราะข้างขวาของสมการบนมากกว่าข้างขวาสมการล่าง →ซ้ายบน ≥ ซ้ายล่าง : induction case เป็นจริง T(n) fib[n] for n>=0 ( จากการพิสูจน์แบบ induction) fib[n] (3/2)n for n>10 ( สามารถพิสูจน์แบบ induction ได้ ) T(n) fib[n] (3/2)n for n>10 (จาก ก) & ข)) T(n) = O(cn) โตเป็น exponential การพิสูจน์โดย Mathametical Induction ต้องพิสูจน์ 2 กรณี base case พิสูจน์ว่ากรณี n ตั้งต้นน้อยๆ เป็นจริง เช่น n = 0, 1 induction case พิสูจน์ว่า ถ้าที่ n <= x ใดๆ เป็นจริงแล้ว หากพิสูจน์ได้ว่าที่ n = x +1 เป็นจริง ดังนั้นสิ่งที่ต้องการพิสูจน์จะเป็นจริงทุก n ใดๆ
Analysis Conclusion Bad Style: T(n) = O(2n2) T(n) = O(n2 + n) T1(n) = O(f(n)) และ T2(n) = O(g(n)) หากมีหลายส่วนต่อกัน คิดส่วนที่ทำมากที่สุด T1(n) + T2(n) = max ( O(f(n)) , O(g(n)) ) // consecutive statements วิเคราะห์จากข้างในออกมา วิเคราะห์ Function call ก่อน loop : ของใน loop * จำนวนครั้งของ loop T1(n) * T2(n) = O(O(f(n)) * O(g(n) ) // loop ถ้าเป็นสมการ polynomial คิดกำลังสูงสุด If statement : maximum (then, else) Bad Style: T(n) = O(2n2) T(n) = O(n2 + n) Correct form: T(n) = O(n2) Bad Style: f(n) O(g(n)) // is implied by defn f(n) O(g(n)) // does not make sense
Performance Measurement Empirical Observation เมื่อเพิ่มค่า n เป็น 2 เท่า แล้ว runtime มากขึ้น * 2 → Linear * 4 → Quadratic * 8 → Cubic เพิ่มเล็กน้อย → Logarithmic เพิ่มมากกว่า 2 เท่า เล็กน้อย → O(n log n)
Big-Oh & Related Notations Other kinds of bounds on asymptotic growth rates if there are positive constants c and n0 such that when n n0 Big Oh f(n) = O(g(n)) f(n) c g(n) Big Omega f(n) = (g(n)) f(n) c g(n) little Oh f(n) = o(g(n)) f(n) < c g(n) or f(n) = O(g(n)) and f(n) (g(n)) little Omega f(n) = (g(n)) f(n) > c g(n) or f(n) = (g(n)) and f(n) (g(n)) Big Theta f(n) = (g(n)) if and only if f(n) = O(g(n)) and f(n) = (g(n))
Limit Comparing 0 f(n) = 3n2 – 100n -25 g(n) = n3 อีกวิธีที่ใช้เปรียบเทียบ f(n) และ g(n) ถ้าค่า lim แกว่ง ใช้วิธีนี้ไม่ได้ เอา f(n) ÷ g(n) แล้ว take lim เมื่อ n→∞ ดูผลที่ได้ 3 กรณี 0 f(n) = 3n2 – 100n -25 g(n) = n3 f(n) โตช้ากว่า g(n), f(n)=o(g(n)) ∞ f(n) = 3n2 – 100n -25 g(n) = n f(n) โตเร็วกว่า g(n), f(n)= (g(n)), g(n)=o(f(n)) c, c ≠ 0, c ≠ ∞ f(n) = 3n2 – 100n -25 g(n) = n2 โตเร็วพอกัน, f(n)= (g(n))
กฏของโลปิตอล (L’Hôpital ‘s rule) ถ้า และ แล้ว = โดย f ’(n) และ g’(n) คือ derivatives ของ f(n) และ g(n) ตามลำดับ
Complex Algorithm Complexity ของ algorithm บางอันสูงมาก และหา average case ได้ยากมาก บางอันยังหาไม่ได้ และ worst case ที่หาได้ก็แย่มาก ไม่สามารถนำมาใช้แทนได้