Quicksort CSE 2320 – Algorithms and Data Structures Vassilis Athitsos University of Texas at Arlington 1.

Slides:



Advertisements
Similar presentations
Algorithms Analysis Lecture 6 Quicksort. Quick Sort Divide and Conquer.
Advertisements

Theory of Computing Lecture 3 MAS 714 Hartmut Klauck.
Sorting Comparison-based algorithm review –You should know most of the algorithms –We will concentrate on their analyses –Special emphasis: Heapsort Lower.
Math 130 Introduction to Computing Sorting Lecture # 17 10/11/04 B Smith: Save until Week 15? B Smith: Save until Week 15? B Smith: Skipped Spring 2005?
1 Today’s Material Medians & Order Statistics – Ch. 9.
CSC 331: Algorithm Analysis Divide-and-Conquer Algorithms.
Spring 2015 Lecture 5: QuickSort & Selection
Sorting. “Sorting” When we just say “sorting,” we mean in ascending order (smallest to largest) The algorithms are trivial to modify if we want to sort.
Quicksort CS 3358 Data Structures. Sorting II/ Slide 2 Introduction Fastest known sorting algorithm in practice * Average case: O(N log N) * Worst case:
25 May Quick Sort (11.2) CSE 2011 Winter 2011.
Quicksort COMP171 Fall Sorting II/ Slide 2 Introduction * Fastest known sorting algorithm in practice * Average case: O(N log N) * Worst case: O(N.
Updated QuickSort Problem From a given set of n integers, find the missing integer from 0 to n using O(n) queries of type: “what is bit[j]
1 Sorting Problem: Given a sequence of elements, find a permutation such that the resulting sequence is sorted in some order. We have already seen: –Insertion.
Data Structures, Spring 2006 © L. Joskowicz 1 Data Structures – LECTURE 4 Comparison-based sorting Why sorting? Formal analysis of Quick-Sort Comparison.
Simple Sorting Algorithms
Quicksort. Quicksort I To sort a[left...right] : 1. if left < right: 1.1. Partition a[left...right] such that: all a[left...p-1] are less than a[p], and.
Sorting Suppose you wanted to write a computer game like Doom 4: The Caverns of Calvin… How do you render those nice (lurid) pictures of Calvin College.
Quicksort. 2 Introduction * Fastest known sorting algorithm in practice * Average case: O(N log N) * Worst case: O(N 2 ) n But, the worst case seldom.
Quicksort.
Quicksort.
Quicksort CIS 606 Spring Quicksort Worst-case running time: Θ(n 2 ). Expected running time: Θ(n lg n). Constants hidden in Θ(n lg n) are small.
Quicksort
Data Structures Review Session 1
Cmpt-225 Sorting – Part two. Idea of Quick Sort 1) Select: pick an element 2) Divide: partition elements so that x goes to its final position E 3) Conquer:
Chapter 7 (Part 2) Sorting Algorithms Merge Sort.
Sorting Chapter 6 Chapter 6 –Insertion Sort 6.1 –Quicksort 6.2 Chapter 5 Chapter 5 –Mergesort 5.2 –Stable Sorts Divide & Conquer.
CS2420: Lecture 11 Vladimir Kulyukin Computer Science Department Utah State University.
Sorting II/ Slide 1 Lecture 24 May 15, 2011 l merge-sorting l quick-sorting.
Computer Algorithms Lecture 10 Quicksort Ch. 7 Some of these slides are courtesy of D. Plaisted et al, UNC and M. Nicolescu, UNR.
Simple Sorting Algorithms. 2 Bubble sort Compare each element (except the last one) with its neighbor to the right If they are out of order, swap them.
Sorting (Part II: Divide and Conquer) CSE 373 Data Structures Lecture 14.
Simple Sorting Algorithms. 2 Outline We are going to look at three simple sorting techniques: Bubble Sort, Selection Sort, and Insertion Sort We are going.
1 Time Analysis Analyzing an algorithm = estimating the resources it requires. Time How long will it take to execute? Impossible to find exact value Depends.
Order Statistics The ith order statistic in a set of n elements is the ith smallest element The minimum is thus the 1st order statistic The maximum is.
The Selection Problem. 2 Median and Order Statistics In this section, we will study algorithms for finding the i th smallest element in a set of n elements.
David Luebke 1 6/3/2016 CS 332: Algorithms Analyzing Quicksort: Average Case.
CS 361 – Chapters 8-9 Sorting algorithms –Selection, insertion, bubble, “swap” –Merge, quick, stooge –Counting, bucket, radix How to select the n-th largest/smallest.
1 CSE 373 Sorting 3: Merge Sort, Quick Sort reading: Weiss Ch. 7 slides created by Marty Stepp
Sorting: Implementation Fundamental Data Structures and Algorithms Klaus Sutner February 24, 2004.
Review 1 Selection Sort Selection Sort Algorithm Time Complexity Best case Average case Worst case Examples.
Deterministic and Randomized Quicksort Andreas Klappenecker.
Analysis of Algorithms CS 477/677 Instructor: Monica Nicolescu Lecture 7.
Divide And Conquer A large instance is solved as follows:  Divide the large instance into smaller instances.  Solve the smaller instances somehow. 
Searching and Sorting Searching: Sequential, Binary Sorting: Selection, Insertion, Shell.
Sorting Fundamental Data Structures and Algorithms Aleks Nanevski February 17, 2004.
Priority Queues, Heaps, and Heapsort CSE 2320 – Algorithms and Data Structures Vassilis Athitsos University of Texas at Arlington 1.
Young CS 331 D&A of Algo. Topic: Divide and Conquer1 Divide-and-Conquer General idea: Divide a problem into subprograms of the same kind; solve subprograms.
David Luebke 1 2/19/2016 Priority Queues Quicksort.
IS 2610: Data Structures Discuss HW 2 problems Binary Tree (continued) Introduction to Sorting Feb 9, 2004.
CSC317 1 Quicksort on average run time We’ll prove that average run time with random pivots for any input array is O(n log n) Randomness is in choosing.
Computer Science 1620 Sorting. cases exist where we would like our data to be in ascending (descending order) binary searching printing purposes selection.
PREVIOUS SORTING ALGORITHMS  BUBBLE SORT –Time Complexity: O(n 2 ) For each item, make (n –1) comparisons Gives: Comparisons = (n –1) + (n – 2)
Quicksort Quicksort is a well-known sorting algorithm that, in the worst case, it makes Θ(n 2 ) comparisons. Typically, quicksort is significantly faster.
Example Algorithms CSE 2320 – Algorithms and Data Structures Alexandra Stefan University of Texas at Arlington Last updated 1/31/
Quicksort This is probably the most popular sorting algorithm. It was invented by the English Scientist C.A.R. Hoare It is popular because it works well.
Sorting & Searching Geletaw S (MSC, MCITP). Objectives At the end of this session the students should be able to: – Design and implement the following.
SORTING AND ASYMPTOTIC COMPLEXITY Lecture 13 CS2110 – Fall 2009.
329 3/30/98 CSE 143 Searching and Sorting [Sections 12.4, ]
Priority Queues, Heaps, and Heapsort CSE 2320 – Algorithms and Data Structures Vassilis Athitsos University of Texas at Arlington 1.
Mergesort CSE 2320 – Algorithms and Data Structures Vassilis Athitsos
Quicksort 1.
Department of Computer and Information Science, School of Science, IUPUI Quicksort Dale Roberts, Lecturer Computer Science, IUPUI
Quick Sort (11.2) CSE 2011 Winter November 2018.
CO 303 Algorithm Analysis And Design Quicksort
Data Structures Review Session
CSE 373 Data Structures and Algorithms
Data Structures & Algorithms
Quicksort.
The Selection Problem.
Presentation transcript:

Quicksort CSE 2320 – Algorithms and Data Structures Vassilis Athitsos University of Texas at Arlington 1

Sorting We have already seen sorting methods in this course. – Selection Sort for arrays. – Insertion Sort for lists. The running time in both cases was Θ(N 2 ) for sorting a set of N items. This running time is OK for small N, but becomes prohibitive for sorting large amounts of data. We will now start reviewing more sophisticated sort methods, with better time complexity. – Typically the time complexity will be Θ(N log N), but there will also be exceptions. 2

The Item Type In general, the array or list we want to sort contains items of some type, that we will call Item. For example, Item can be defined to be: – int – double – char * – a pointer to some structure. Most of the sorting algorithms we will study work on any Item type. In our code, we will specify the Item type as needed using typedef. For example: typedef int Item; 3

The Key If Item is a pointer to a structure, then we need to specify which member variable of that structure will be used for sorting. This member variable is called the key of the object. For example, we could have a structure for a person, that includes age, weight, height, address, phone number. – If we want to sort based on age, then the key of the structure is age. – If we want to sort based on height, then the key of the structure is height. For simple data types (numbers, strings), the key of the object can be itself. In our code, we will specify the key as needed using a #define macro. For example: #define key(A) (A) 4

The Comparison Operator We are sorting in some kind of order. The comparison operator C is what defines this order. The comparison operator C is a function that takes two objects (of type Item) as arguments, and returns True or False. A sequence A 1, A 2, A 3,..., A K is sorted if, for all i between 1 and K-1: – C(A i, A i+1 ) is True, OR A i is equal to A i+1. 5

The Comparison Operator Examples of such operators:. However, they can be more complicated: – Case-sensitive alphabetical ordering. – Case-insensitive alphabetical ordering. –... The textbook code (unfortunately) calls every such operator less, even if it is set to >. We define less as needed using a #define macro. For example: #define less(A, B) (key(A) < key(B)) 6

Additional Notation To save lines of code, the textbook defines the following macros: exch(A, B): swaps the values of A and B. #define less(A, B) (key(A) < key(B)) compexch(A, B): swap values of A and B ONLY IF less(A, B). #define compexch(A, B) if (less(B, A)) exch(A, B) 7

Summary of Definitions and Macros In a specific implementation, we must define: – Item – Key – less For example: typedef int Item; #define key(A) (A) #define less(A, B) (key(A) < key(B)) In all implementations, we use macros exch and compexch: #define exch(A, B) { Item t = A; A = B; B = t; } #define compexch(A, B) if (less(B, A)) exch(A, B) 8

Quicksort Overview Quicksort is the most popular sorting algorithm. Extensively used in popular languages (such as C) as the default sorting algorithm. The average time complexity is Θ(Ν log N). Interestingly, the worst-case time complexity is Θ(N 2 ). However, if quicksort is implemented appropriately, the probability of the worst case happening is astronomically small. 9

Partitioning Quicksort is based on an operation called "partitioning". Partitioning takes three arguments: – An array a[]. – A left index L. – A right index R. Partitioning rearranges array elements a[L], a[L+1],..., a[R]. – Elements before L or after R are not affected. Partitioning returns an index i such that: – When the function is done, a[i] is what a[R] was before the function was called. We move a[R] to a[i]. – All elements between a[L] and a[i-1] are not greater than a[i]. – All elements between a[i+1] and a[R] are not less than a[i]. 10

Partitioning Example: suppose we have this array a[]: What does partition(a, 0, 9) do in this case? 11 position value

Partitioning Example: suppose we have this array a[]: What does partition(a, 0, 9) do in this case? The last element of the array is is called the pivot. – Array a[] has: – 3 elements less than the pivot. – 6 elements greater than the pivot. Array a[] is rearranged so that: – First we put all values less than the pivot (35). – Then, we put the pivot. – Then, we put all values greater than the pivot. partition(a, 0, 9) returns the new index of the pivot, which is position value

Partitioning Example: suppose we have this array a[]: How does array a[] look after we call partition(a, 0, 9)? Note that: – Items at positions 0, 1, 2 are not necessarily in sorted order. – However, items at positions 0, 1, 2 are all <= 35. – Similarly: items at positions 4,..., 9 are not necessarily in sorted order. – However, items at positions 4,..., 9 are all >= position value position value

Partitioning Example: suppose we have this array a[]: What does partition(a, 2, 6) do in this case? 14 position value

Partitioning Example: suppose we have this array a[]: What does partition(a, 2, 6) do in this case? a[6] = is the pivot. – Array a[2, …, 6] has: – 2 elements less than the pivot. – 2 elements greater than the pivot. Array a[2, 6] is rearranged so that: – First we put all values less than the pivot (45). – Then, we put the pivot. – Then, we put all values greater than the pivot. partition(a, 2, 6) returns the new index of the pivot, which is position value

Partitioning Example: suppose we have this array a[]: How does array a[] look after we call partition(a, 2, 6)? Note that: – Items at positions 2,3 are not necessarily in sorted order. – However, items at positions 2, 3 are all <= 45. – Similarly: items at positions 5, 6 are not necessarily in sorted order. – However, items at positions 5, 6 are all >= 45. – Items at positions 0, 1 and at positions 7, 8, 9, are not affected. 16 position value position value

Partitioning Code int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; } 17

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = -1 j = 9 18 position value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = -1 j = 9 i = 0 a[i] = 17 < 35 i = 1; a[i] = is not < 35, break! 19 position value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 1 j = 9 j = 8 a[j] = is not < 10, break! 20 int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; } position0i= value

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 1 j = 8 i is not >= j, we don't break. swap values of a[i] and a[j]. a[i] becomes 10. a[j] becomes position0i= j=89 value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 1 j = 8 i = 2 a[i] = is not < 35, break! 22 position01i=234567j=89 value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 2 j = 8 j = 7 a[j] = 80. j = 6 a[j] = position01i=2345j=6789 value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 2 j = 8 j = 5, a[j] = 40 j = 4, a[j] = 60 j = 3, a[j] = < 35, break! 24 position01i=2j= value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 2 j = 3 i is not >= j, we don't break. swap values of a[i] and a[j]. a[i] becomes 30. a[j] becomes position01i=2j= value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 2 j = 3 i = 3 a[i] = 70 > 35, break! 26 position012i=j= value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 3 j = 3 j = 2 a[j] = 30 > 35, break! 27 position01j=2i= value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 3 j = 2 i >= j, we break! 28 position01j=2i= value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

How Partitioning Works partition(a, 0, 9): v = a[9] = 35 i = 3 j = 2 a[i] becomes 35 a[r] becomes 70 we return i, which is 3. DONE!!! 29 position01j=2i= value int partition(Item a[], int l, int r) { int i = l-1, j = r; Item v = a[r]; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a[i], a[j]); } exch(a[i], a[r]); return i; }

Quicksort void quicksort(Item a[], int length) { quicksort_aux(a, 0, length-1); } void quicksort_aux(Item a[], int l, int r) { int i; if (r <= l) return; i = partition(a, l, r); quicksort_aux(a, l, i-1); quicksort_aux(a, i+1, r); } 30 To sort array a, quicksort works as follows: Do an initial partition of a, that returns some position i. Recursively do quicksort on: – a[0],..., a[i-1] – a[i+1],..., a[length-1] What are the base cases?

Quicksort void quicksort(Item a[], int length) { quicksort_aux(a, 0, length-1); } void quicksort_aux(Item a[], int l, int r) { int i; if (r <= l) return; i = partition(a, l, r); quicksort_aux(a, l, i-1); quicksort_aux(a, i+1, r); } 31 To sort array a, quicksort works as follows: Do an initial partition of a, that returns some position i. Recursively do quicksort on: – a[0],..., a[i-1] – a[i+1],..., a[length-1] What are the base cases? – Array length 1 (r == l). – Array length 0 (r < l).

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); 32 position value Before partition(a, 0, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); 33 position value After partition(a, 0, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 34 position value After partition(a, 0, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 4, 9); 35 position value Before partition(a, 0, 2)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 4, 9); 36 position value After partition(a, 0, 2) (no change)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 0, 1); quicksort_aux(a, 3, 2); quicksort_aux(a, 4, 9); 37 position value After partition(a, 0, 2) (no change)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 0, 1); 0 = partition(a, 0, 1); quicksort_aux(a, 3, 2); quicksort_aux(a, 4, 9); 38 position value Before partition(a, 0, 1)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 0, 1); 0 = partition(a, 0, 1); quicksort_aux(a, 3, 2); quicksort_aux(a, 4, 9); 39 position value After partition(a, 0, 1)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 0, 1); 0 = partition(a, 0, 1); quicksort_aux(a, 0, -1); quicksort_aux(a, 1, 1); quicksort_aux(a, 3, 2); quicksort_aux(a, 4, 9); 40 position value After partition(a, 0, 1) Base cases. Nothing to do.

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); 2 = partition(a, 0, 2) quicksort_aux(a, 0, 1); 0 = partition(a, 0, 1); quicksort_aux(a, 3, 2); quicksort_aux(a, 4, 9); 41 position value After partition(a, 0, 1) Base case. Nothing to do.

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); 42 position value Before partition(a, 4, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); 43 position value After partition(a, 4, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); quicksort_aux(a, 8, 9); 44 position value After partition(a, 4, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); 5 = partition(a, 4, 6); quicksort_aux(a, 8, 9); 45 position value Before partition(a, 4, 6)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); 5 = partition(a, 4, 6); quicksort_aux(a, 8, 9); 46 position value After partition(a, 4, 6)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); 5 = partition(a, 4, 6); quicksort_aux(a, 4, 4); quicksort_aux(a, 6, 6); quicksort_aux(a, 8, 9); 47 position value After partition(a, 4, 6) Base cases. Nothing to do.

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); quicksort_aux(a, 8, 9); 8 = partition(a, 8, 9); 48 position value Before partition(a, 8, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); quicksort_aux(a, 8, 9); 8 = partition(a, 8, 9); 49 position value After partition(a, 8, 9)

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); quicksort_aux(a, 8, 9); 8 = partition(a, 8, 9); quicksort_aux(a, 8, 7); quicksort_aux(a, 9, 9); 50 position value After partition(a, 8, 9) Base cases. Nothing to do.

How Quicksort Works quicksort_aux(a, 0, 9); 3 = partition(a, 0, 9); quicksort_aux(a, 0, 2); quicksort_aux(a, 4, 9); 7 = partition(a, 4, 9); quicksort_aux(a, 4, 6); quicksort_aux(a, 8, 9); 8 = partition(a, 8, 9); quicksort_aux(a, 8, 7); quicksort_aux(a, 9, 9); 51 position value After partition(a, 8, 9) Base cases. Nothing to do. Done!!! All recursive calls have returned. The array is sorted.

Worst-Case Time Complexity The worst-case of quicksort is interesting: Quicksort has the slowest running time when the input array is already sorted. partition(a, 0, 9): – scans 10 elements, makes no changes, returns 9. partition(a, 0, 8): – scans 9 elements, makes no changes, returns 8. partition(a, 0, 7): – scans 8 elements, makes no changes, returns 7. Overall, worst-case time is N+(N-1)+(N-2)+…+1 = Θ(N 2 ). 52 position value

Best-Case Time Complexity Overall, the worst-case happens when the array is partitioned in an imbalanced way: – One item, or very few items, on one side. – Everything else on the other side. The best case time complexity for quicksort is when the array is partitioned in a perfectly balanced way. I.e., when the pivot is always the median value in the array. Let T(N) be the best-case running time complexity for quicksort. T(N) = N + 2 * T(N/2) Why? Because to sort the array: – We do N operations for the partition. – We do to recursive calls, and each call receives half the data. 53

Best-Case Time Complexity For convenience, let N = 2 n. Assuming that the partition always splits the set into two equal halves, we get: T(2 n ) = 2 n + 2 * T(2 n-1 ) = 1*2 n * T(2 n-1 )step 1 = 2*2 n * T(2 n-2 ) step 2 = 3*2 n * T(2 n-3 ) step 3 … = i*2 n + 2 i * T(2 n-i ) step i … = n*2 n + 2 n * T(2 n-n ) step n = lg N * N + N * T(0) = Θ(Ν lg N). 54

Average Time Complexity The worst-case time complexity is Θ(N 2 ). The best-case time complexity is Θ(N lg N). Analyzing the average time complexity is beyond the scope of this class. It turns out that the average time complexity is also Θ(N lg N). On average, quicksort performance is close to that of the best case. Why? Because, usually, the pivot value is "close enough" to the 50-th percentile to achieve a reasonably balanced partition. – For example, half the times the pivot value should be between the 25-th percentile and the 75th percentile. 55

Improving Performance The basic implementation of quicksort that we saw, makes a partition using the rightmost element as pivot. – This has the risk of giving a pivot that is not that close to the 50th percentile. – When the data is already sorted, the pivot is the 100th percentile, which is the worst-case. 56

Improving Performance We can improve performance by using as pivot the median of three values: – The leftmost element. – The middle element. – The rightmost element. Then, the pivot has better chances of being close to the 50th percentile. If the file is already sorted, the pivot is the median. Thus, already sorted data is: – The worst case (slowest running time) when the pivot is the rightmost element. – The best case (fastest run time) when the pivot is the median of the leftmost, middle, and rightmost elements. 57

The Selection Problem The selection problem is defined as follows: Given a set of N numbers, find the K-th smallest value. K can be anything. Special cases: – K = 1: we are looking for the minimum value. – K = N/2: we are looking for the median value. – K = N: we are looking for the maximum value. However, K can take other values as well. 58

Solving The Selection Problem Special cases: K = 1: we are looking for the minimum value. – We can find the solution in linear time, by just going through the array once. K = N: we are looking for the maximum value. – Again, we can find the solution in linear time. What about K = N/2, i.e., for finding the median? An easy (but not optimal) approach would be: – Sort the numbers using quicksort. – Return the middle position in the array. – Average time complexity: Θ(N lg N). 59

Solving The Selection Problem It turns out we can solve the selection problem in linear time (on average), using an algorithm very similar to quicksort. 60 void quicksort(Item a[], int length) { quicksort_aux(a, 0, length-1); } void quicksort_aux(Item a[], int L, int R) { if (R <= L) return; int i = partition(a, L, R); quicksort_aux(a, L, i-1); quicksort_aux(a, i+1, R); } int select(a[], int length, int k) { return select_aux(a, 0, length-1, k); } int select_aux(Item a[], int L, int R, int k) { if (R <= L) return; int i = partition(a, L, R); if (i > k-1) return select_aux(a, L, i-1, k); if (i < k-1) return select_aux(a, i+1, R, k); return a[k-1]; }

Solving The Selection Problem Why does this work? Suppose that some partition(a, L, R) returned k-1. That means that: Value a[k-1] was the pivot used in that partition. Everything to the left of a[k-1] is <= a[k-1]. Everything to the right of a[k-1] is >= a[k-1]. Thus, a[k-1] is the k-th smallest value. 61 int select(a[], int length, int k) { return select_aux(a, 0, length-1, k); } int select_aux(Item a[], int L, int R, int k) { if (R <= L) return; int i = partition(a, L, R); if (i > k-1) return select_aux(a, L, i-1, k); if (i < k-1) return select_aux(a, i+1, R, k); return a[k-1]; }

Solving The Selection Problem Suppose that some partition(a, L, R) returned i > k-1. Value a[i] was the pivot used in that partition. Everything to the left of a[i] is <= a[i]. Everything to the right of a[i] is >= a[i]. Thus, a[i] is the i-th smallest value. Since k < i, the answer is among items a[L],..., a[i-1]. 62 int select(a[], int length, int k) { return select_aux(a, 0, length-1, k); } int select_aux(Item a[], int L, int R, int k) { if (R <= L) return; int i = partition(a, L, R); if (i > k-1) return select_aux(a, L, i-1, k); if (i < k-1) return select_aux(a, i+1, R, k); return a[k-1]; }

Solving The Selection Problem Suppose that some partition(a, L, R) returned i < k-1. Value a[i] was the pivot used in that partition. Everything to the left of a[i] is <= a[i]. Everything to the right of a[i] is >= a[i]. Thus, a[i] is the i-th smallest value. Since k > i, the answer is among items a[i+1],..., a[R]. 63 int select(a[], int length, int k) { return select_aux(a, 0, length-1, k); } int select_aux(Item a[], int L, int R, int k) { if (R <= L) return; int i = partition(a, L, R); if (i > k-1) return select_aux(a, L, i-1, k); if (i < k-1) return select_aux(a, i+1, R, k); return a[k-1]; }

Selection Time Complexity The worst-case time complexity of selection is equivalent to that for quicksort: – The pivot is the smallest or the largest element. – Then, we did a lot of work to just eliminate one item. Overall, worst-case time is N+(N-1)+(N-2)+…+1 = Θ(N 2 ). – Same as for quicksort. 64

Best-Case Time Complexity The best case time complexity for selection is also similar to the one for quicksort: – When the array is partitioned in a perfectly balanced way. – That is, when the pivot is always the median value in the array. Let T Q (N) be the best-case running time complexity for quicksort. Let T S be the best-case running time complexity for selection. T Q (N) = N + 2 * T Q (N/2). T S (N) = N + T S (N/2). Why is the T S different than the T Q recurrence? In quicksort, we need to process both parts of the partition. In selection, we only need to process one part of the partition. 65

Best-Case Time Complexity For convenience, let N = 2 n. Assuming that the partition always splits the set into two equal halves, we get: T S (2 n ) = 2 n + T S (2 n-1 ) = 2 n + T S (2 n-1 )step 1 = 2 n + 2 n-1 + T S (2 n-2 ) step 2 = 2 n + 2 n n-2 + T S (2 n-3 ) step 3 … = 2 n + 2 n n-2 + … T S (0) step n = 2 n constant = 2*N + constant = Θ(Ν). 66

Average Time Complexity The worst-case time complexity is Θ(N 2 ). The best-case time complexity is Θ(N). The average time complexity is also Θ(N). On average, selection performance is close to that of the best case. Why? Because, exactly as in quicksort, usually, the pivot value is "close enough" to the 50-th percentile to achieve a reasonably balanced partition. 67