Tirgul 12 Data Structures 1 Sorting Algorithms n

  • Slides: 75
Download presentation
Tirgul 12 Data Structures 1

Tirgul 12 Data Structures 1

Sorting Algorithms n http: //www. sorting-algorithms. com/ 2

Sorting Algorithms n http: //www. sorting-algorithms. com/ 2

Recurrence Relations to Know and Love n T(n) = T(n – 1) + O(n)

Recurrence Relations to Know and Love n T(n) = T(n – 1) + O(n) Selection / Insertion / Bubble Sort O(n 2) n T(n) = T(n – 1) + O(1) Sequential Search O(n) n T(n) = T(n/2) + O(1) Binary Search O(log 2 n)

Linked Lists n n n Separate the logical order of items from their physical

Linked Lists n n n Separate the logical order of items from their physical order in memory Each item points to the location of the next item Each item in the list is called a node Dynamically allocate nodes as needed Linked lists may also be used to implement other data structures, like queues and stacks Always remember that when a link to an item is destroyed – the item can not be reached! 4

Linked List Nodes class List { Object data; List next; } head next data

Linked List Nodes class List { Object data; List next; } head next data next null data 5

Iterators n n Provide an efficient way to traverse a data structure while protecting

Iterators n n Provide an efficient way to traverse a data structure while protecting its encapsulation Data structure provides an object implementing an iterator interface: public interface Object. List. Iterator { public boolean has. Next(); public Objecct next(); } Returns true iff there are more Gets the next item in the list items to iterate over 6

Using iterators n n The iterator class must have access to the data structure’s

Using iterators n n The iterator class must have access to the data structure’s internal members, so it is usually defined as an inner class or part of the same package Using an iterator to print a list: Object. List. Iterator it=list. iterator(); while (it. has. Next()) System. out. println(it. next()); 7

Linked List implementation public class Object. List { protected static class List { Object

Linked List implementation public class Object. List { protected static class List { Object data; Nested class List next; List(Object d, List n){data=d; next=n; } } The first Node in the list protected List head; public Object. List() {head=null; } 8

Linked List implementation Recursively returns a copy of the sub-list starting with the given

Linked List implementation Recursively returns a copy of the sub-list starting with the given node protected static List clone(List node) { if (node==null) return null; return new List(node. data, clone(node. next)); } public Object. List(Object. List list) { head = clone(list. head); Copy constructor } 9

Linked List implementation public void add. First(Object d){ head = new List(d, head); }

Linked List implementation public void add. First(Object d){ head = new List(d, head); } public Object remove. First(){ Object d = head. data; head = head. next; return d; What does this method assume? } 10

Linked List implementation public boolean is. Empty(){ return head==null; } public String to. String(){

Linked List implementation public boolean is. Empty(){ return head==null; } public String to. String(){ String s = “”; for(List n=head; n!=null; n=n. next) s += n. data. to. String() + “ “; return s; Loop over all nodes } in the list 11

Linked List implementation protected class My. Iterator implements Object. List. Iterator { Inner class

Linked List implementation protected class My. Iterator implements Object. List. Iterator { Inner class List current; My. Iterator() {current=head; } public boolean has. Next() {…} public Object next() {…} } public Object. List. Iterator iterator() { return new My. Iterator(); Return an iterator } for this list 12

Stack n n n A stack is a Last-In-First-Out (LIFO) data structure The stack

Stack n n n A stack is a Last-In-First-Out (LIFO) data structure The stack interface is: push, pop, is. Empty Implementing a stack using a linked list is trivial 13

Queue n n A queue is a First-In-First-Out (FIFO) data structure The queue interface

Queue n n A queue is a First-In-First-Out (FIFO) data structure The queue interface is: enqueue, dequeue, is. Empty Enqueue - Enter new element to queue. Dequeue – Remove the element which was first entered the queue. 14

Queue n Implementation of Queue with linked lists can be done in two ways:

Queue n Implementation of Queue with linked lists can be done in two ways: n n n Enqueue to tail, dequeue from head. Enqueue to head, dequeue from tail. In order to implement a queue using the second option, we need a remove. Last method n n Iterate over the entire list, or Use a doubly-linked list with a tail data member pointing to the last node 15

Enqueue to tail, dequeue from head – from the lecture public class Queue {

Enqueue to tail, dequeue from head – from the lecture public class Queue { private List head, tail; public Queue() { head = tail = null; } public boolean is. Empty() { return head == null; } public void enque(int x) { List tmp = new List(x, null); if (tail!=null) tail. set. Next(tmp); tail = tmp; if (head == null) head = tail; } public int deque() { assert !is. Empty(); int x = head. get. Data(); head = head. get. Next(); if (head == null) tail = null; return x; }}

remove. Last (no tail) public Object remove. Last() { if (head. next == null)

remove. Last (no tail) public Object remove. Last() { if (head. next == null) // singleton return remove. First(); List before = head; List after = head. next; while (after. next != null) { before = after; after = after. next; } What does this method assume? before. next = null; return after. data; } 17

A doubly-linked list with a tail public class Object. List { protected static class

A doubly-linked list with a tail public class Object. List { protected static class List { Object data; List next, prev; List(Object d, List p, List n) { data=d; prev=p; next=n; } } protected List head, tail; public Object. List() { head = tail = null; } 18

A doubly-linked list with a tail public void add. First(Object d) { List node

A doubly-linked list with a tail public void add. First(Object d) { List node = new List(d, null, head); if (head == null) // list was empty tail = node; else // connect old head to new node head. prev = node; // update head = node; } 19

A doubly-linked list with a tail public Object remove. First() { Object d =

A doubly-linked list with a tail public Object remove. First() { Object d = head. data; head = head. next; if (head == null) // list is now empty tail = null; else { // disconnect old head. prev. next = null; head. prev = null; } What does this return d; method assume? } 20

A doubly-linked list with a tail public Object remove. Last(){ Object d = tail.

A doubly-linked list with a tail public Object remove. Last(){ Object d = tail. data; tail = tail. prev; if (tail == null) // list is now empty head = null; else { // disconnect old tail. next. prev = null; tail. next = null; } What does this return d; method assume? } 21

Count. Int. List n n Each integer will appear at most once in the

Count. Int. List n n Each integer will appear at most once in the list Maintain a counter of how many times each number was added Keep the list sorted The input 5, 2, 7, 5, 5, 7 results in the following Count. Int. List: data 2 5 7 count 1 3 2 null 22

Count. Int. List public class Count. Int. List { protected static class List {

Count. Int. List public class Count. Int. List { protected static class List { int data; int count; List next; List(int d, List n) { data=d; count=1; next=n; } } protected List head; public Count. Int. List() {head=null; } 23

Count. Int. List protected List lower. Bound(int d) { if(head == null || d

Count. Int. List protected List lower. Bound(int d) { if(head == null || d < head. data) return null; List before = head; List after = head. next; while(after != null && after. data <= d){ before = after; after = after. next; In order to add new data d, we need to find the Node } containing the largest data ≤ d return before; } 24

Count. Int. List Add the given data to the Count. Int. List public void

Count. Int. List Add the given data to the Count. Int. List public void add(int d) { List prev = lower. Bound(d); if(prev==null) // add new Node at head = new List(d, head); else if (prev. data==d) prev. count++; //update existing Node else // add new Node after prev. next = new List(d, prev. next); } 25

Student grade DB public class Student { We want a DB of students sorted

Student grade DB public class Student { We want a DB of students sorted by their private String name; grades in each subject private int[] grades; public Student(String name, int[] grades) {…} public Student(Student s) {…} public int get. Grade(int subject) { return grades[subject]; } public String get. Name() {return name; } } 26

A multi-linked list name grades next[] Alice Bob {99, 75, 99} null {80, 75}

A multi-linked list name grades next[] Alice Bob {99, 75, 99} null {80, 75} {75, 99, 80} null head[1] Charlie head[2] head[0] 27

Grades DB public class Grades. DB { public static final int SUBJECT_NUM = 3;

Grades DB public class Grades. DB { public static final int SUBJECT_NUM = 3; protected static class List { Student data; List[] next = new List[SUBJECT_NUM]; List(Student s) {data = new Student(s); } int grade(int i) {return data. get. Grade(i); } } protected List[] head = new List[SUBJECT_NUM]; 28

Grades DB public void add(Student stud) { Add a student to the DB List

Grades DB public void add(Student stud) { Add a student to the DB List node = new List(stud); for (int i=0; i<SUBJECT_NUM; i++) add(i, node); } protected void add(int i, List node) { Add a node List prev = lower. Bound(i, node. data); to list #i if (prev==null) { // add node at head node. next[i] = head[i]; head[i] = node; } else { // add node after prev node. next[i] = prev. next[i]; prev. next[i] = node; } } 29

Grades DB Return the node which should come before the given student in list

Grades DB Return the node which should come before the given student in list #i protected List lower. Bound(int i, Student stud) { int grade = stud. get. Grade(i); if (head[i]==null || grade < head[i]. grade(i)) return null; List before = head[i]; List after = head[i]. next[i]; while (after!=null && after. grade(i)<=grade) { before = after; after = after. next[i]; } return before; } 30

Grades DB Return the student names sorted by their grade in the given subject

Grades DB Return the student names sorted by their grade in the given subject public String get. Ranking(int subject) { String ranking = “”; for (List n = head[subject]; n!=null; n = n. next[subject]) ranking += n. data. get. Name() + ‘ ‘; return ranking; } For example, get. Ranking(2) returns “Bob Charlie Alice” 31

Linked Lists vs. Arrays Operation Linked List Array Insert at head O(1) O(n) Insert

Linked Lists vs. Arrays Operation Linked List Array Insert at head O(1) O(n) Insert at middle O(n), O(1) given a reference O(n) Remove from head O(1) O(n) Remove from middle O(n), O(1) given a reference O(n) Append O(n), O(1) given a reference O(n+m) Find k-th element O(k) O(1) Search unsorted O(n) Search sorted O(n) O(log n) 32

Tree Structures n n A tree is a hierarchical structure that places elements in

Tree Structures n n A tree is a hierarchical structure that places elements in nodes along branches that originate from a root. Nodes in a tree are subdivided into levels in which the topmost level holds the root node. 33

Binary Tree n In a binary tree each node has at most two successors.

Binary Tree n In a binary tree each node has at most two successors. 34

Tree Terminology 35

Tree Terminology 35

Tree Terminology 36

Tree Terminology 36

Height of a Binary Tree n The height of a binary tree is the

Height of a Binary Tree n The height of a binary tree is the length of the longest path from the root to a leaf node. Let TN be the subtree with root N and TL and TR be the roots of the left and right subtrees of N. Then { height(N) = height(TN) = -1 1+max( height(TL), height(TR)) if TN is empty if TN not empty 37

Binary Search Tree n A binary search tree is a binary tree where every

Binary Search Tree n A binary search tree is a binary tree where every node's left subtree holds values less than the node's value, and every right subtree holds values greater. 17 11 19 38

Recursive Binary Tree-Scan Algorithms n To scan a tree recursively we must visit the

Recursive Binary Tree-Scan Algorithms n To scan a tree recursively we must visit the node (N), scan the left subree (L), and scan the right subtree (R). The order in which we perform the N, L, R tasks determines the scan algorithm. 39

Inorder Scan n The inorder scan of a tree visits the left subtree L,

Inorder Scan n The inorder scan of a tree visits the left subtree L, visits the node N, then visits the right subtree R. To scan the entire tree, begin with the root. Scan order: B D A E C 40

Recursive Scanning Example Preorder (NLR): Inorder (LNR): Postorder (LRN): A D G B G

Recursive Scanning Example Preorder (NLR): Inorder (LNR): Postorder (LRN): A D G B G D D B B G A H C H I E E E H I F I C C F F A 41

Binary trees in Java public class Node { protected Comparable data; protected Node left,

Binary trees in Java public class Node { protected Comparable data; protected Node left, right; public Node(Comparable data) { data = data; left = right = null; } public void add. Right(Node node) { right = node; } public void add. Left(Node node) { left = node; } public Node get. Right() { return right; } } //class public Node get. Left() { return left; } public Comparable get. Data() { return data; } 42

Binary Search Tree public class Bin. Tree { protected Node root; protected int size;

Binary Search Tree public class Bin. Tree { protected Node root; protected int size; public Bin. Tree() { size = 0; } public void add(Comparable data) { add(data, root); size++; } 43

Recursive method to add private void add(Comparable data, Node son, Node father) { //stop

Recursive method to add private void add(Comparable data, Node son, Node father) { //stop the recursion, we have reached a leaf if (son == null) { if (father == null) { //this leaf is the root = new Node(data); } else { //just a regular leaf if ((father. get. Data()). compare(data) > 0) father. add. Left(new Node(data)); else father. add. Right(new Node(data)); } } else { if ((son. get. Data()). compare(data) == 1) add(data, son. get. Left(), son); else add(data, son. get. Right(), son); } } 44

Recursive method to travel /** * Recursive method: * Traversal of the tree (inorder).

Recursive method to travel /** * Recursive method: * Traversal of the tree (inorder). */ private void traverse(Node node) { if (node != null) { traverse(node. get. Left()); System. out. println(node. get. Data()); traverse(node. get. Right()); } } 45

Sorting an array using a binary search tree n n Inorder traversal of a

Sorting an array using a binary search tree n n Inorder traversal of a binary search tree always gives a sorted sequence of the values. Given a set of unordered elements, the following method can be used to Sort the elements: 1. construct a binary search tree whose keys are those elements, and then 2. perform an inorder traversal of this tree. 46

Example Given the following array: 2 3 8 4 5 7 6 1 n

Example Given the following array: 2 3 8 4 5 7 6 1 n 2. 5 2. 4 2 The resulting tree is: 3 1 8 2. 5 2. 4 4 5 7 6 47

Sorting an array using a binary search tree Inorder traversal of this tree will

Sorting an array using a binary search tree Inorder traversal of this tree will result in: 2 1, 2, 2. 4, 2. 5, 3, 4, 5, 6, 7, 8 n 3 1 8 2. 5 n What is the complexity of binary search tree sorting? 2. 4 4 5 7 6 48

Sorting an array using a binary search tree n n n Insertion of element

Sorting an array using a binary search tree n n n Insertion of element into binary search tree in the average case is: O(log(n)). Inorder traversal - O(n)). Total complexity - O((n)log(n)). What is the complexity in the worst case? 49

Expression trees n n In the current exercise you are required to represent a

Expression trees n n In the current exercise you are required to represent a mathematical expression as a tree. The tree nodes are instances of the classes: Number, Variable or Operator, (all of them implement the provided Expression interface). 50

Expression trees An expression tree for the expression: (3+4)*5 An expression tree for the

Expression trees An expression tree for the expression: (3+4)*5 An expression tree for the expression: 3+4*5 51

Building an expression tree from an expression n n You are provided with a

Building an expression tree from an expression n n You are provided with a tokenizer that tells you the type of the next element in the expression. One of your goals is to write the class Parser, that builds a tree from String, using Tokenizer. 52

Expression n To build a tree composed of Number, Variable and Operator, recursively break

Expression n To build a tree composed of Number, Variable and Operator, recursively break expression into blocks of: Term, Factor and Expression can be: Term Expression + Term Expression – Term 53 Term can be: Factor Term * Factor Term / Factor can be: Number Variable (Expression) [meaning: Expression inside brackets]

Example: parse. Expression[“ 8+5*(2 -x)”] parse. Expression [“ 8”] parse. Term [“ 5*(2 -x)”]

Example: parse. Expression[“ 8+5*(2 -x)”] parse. Expression [“ 8”] parse. Term [“ 5*(2 -x)”] + parse. Term [“ 5”] parse. Term[“ 8”] parse. Factor[“ 8”] Number[“ 8”] parse. Factor[“ 5”] Number[“ 5”] parse. Factor [“(2 -x)”] * ( parse. Expression [“ 2”] parse. Term[“ 2”] parse. Expression ) [“ 2 -x”] - parse. Term [“x”] parse. Factor[“ 2”] Number[“ 2”] Variable[“x”]

And the resulted tree for: 8+5*(2 -x) is: + * 8 5 2 x

And the resulted tree for: 8+5*(2 -x) is: + * 8 5 2 x

public static boolean check. Palindrom 2(Stack s 1, int num. Of. Elements) int i;

public static boolean check. Palindrom 2(Stack s 1, int num. Of. Elements) int i; int temp. Val=0; Queue q 2=new Queue(); // move all items to q 2 and for (i=1; i<=num. Of. Elements; i++){ temp. Val=q 1. dequeue (); q 2. enqueue(temp. Val); } // return half of the item to the original stack for (i=1; i<=num. Of. Items/2; i++){ temp. Val=q 2. dequeue(); s 1. push(temp. Val); } //if the number of items is odd: ignore middle item. if ((num. Of. Items % 2) != 0) temp. Val=q 2. dequeue(); // now the q 2 holds half of the items in a reversed //order, and s 1 holds half of the item in their original //order. Compare the items for (i=1; i<=num. Of. Items/2; i++){ { if (s 1. pop()!=q 2. dequeue()) return false; } return true; }

Ternary Search static int Ternary(int []data, int key) { int pivot 1, pivot 2,

Ternary Search static int Ternary(int []data, int key) { int pivot 1, pivot 2, lower=0, upper=data. length-1; do { pivot 1 = (upper-lower)/3+lower; pivot 2 = 2*(upper-lower)/3+lower; if (data[pivot 1] > key){ upper = pivot 1 -1; } else if (data[pivot 2] > key){ upper = pivot 2 -1; lower = pivot 1+1; } else { lower = pivot 2+1; } } while((data[pivot 1] != key) && (data[pivot 2] != key) && (lower <= upper)); if (data[pivot 1] == key) return pivot 1; if (data[pivot 2] == key) return pivot 2; else return -1; } 62

Complexity • Just like binary search, but instead of dividing to two, we divide

Complexity • Just like binary search, but instead of dividing to two, we divide to three. • Same analysis as in binary search can show that the complexity is O(nlog 3 n). • We note that: logan = logbn/logba • Therefore O(nlog 3 n)=O(nlogn) 63

Find Sum x+y=z static boolean Find. Sum(int []data, int z){ for (int i=0; i

Find Sum x+y=z static boolean Find. Sum(int []data, int z){ for (int i=0; i < data. length; i++){ for (int j=i+1; j<data. length; j++){ if (data[i]+data[j] == z){ System. out. println("x=" + data[i] + " and y=" + data[j]); return true; } } } return false; } How do we show the complexity? 64

Complexity Remember the analysis for Bubble Sort: • First loop has n iterates. –

Complexity Remember the analysis for Bubble Sort: • First loop has n iterates. – Inner loop: –

Find Sum in sorted array x+y=z static boolean Find. Sum. Sorted(int []data, int z){

Find Sum in sorted array x+y=z static boolean Find. Sum. Sorted(int []data, int z){ int lower=0, upper=data. length-1; while ((data[lower]+data[upper] != z) && (lower < upper)) { if (data[lower]+data[upper] > z) upper--; else if (data[lower]+data[upper] < z) lower++; } if (lower >= upper) { return false; } else { System. out. println("x=" + data[lower] + " and y=" + data[upper]); } return true; } Complexity? 66

Sample Question 1 • You are given an unsorted array of “Flat” objects, which

Sample Question 1 • You are given an unsorted array of “Flat” objects, which have a method get. Num( ) that returns a value between 1 and 4 • Sort the array of objects in time O(n), calling get. Num( ) no more than once on each object • Do not create new heap objects 3 1 4 4 2 3 1 1 [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Question 1 • This was a moed bet question; many students did a “count-sort”,

Question 1 • This was a moed bet question; many students did a “count-sort”, which they had learned in the second semester • “Run through the array, count how many times each object appears, shift objects around” • This did not satisfy the requirement to call get. Num( ) no more than once on each object • A correct answer is a simple extension of the Dutch Flag problem solution

public static void sort. Flats (Flat[] flats) { int border 1 = -1; int

public static void sort. Flats (Flat[] flats) { int border 1 = -1; int border 2 = 0; int border 3 = flats. length-1; int border 4 = flats. length; do { switch ( flats[border 2]. get. Num( ) ) { case 1: border 1++; swap(flats, border 1, border 2); border 2++; break; case 2: border 2++; break; case 3: swap(flats, border 2, border 3); border 3 --; break; case 4: border 4 --; swap(flats, border 2, border 4); if (border 3 < border 4) swap(flats, border 2, border 3); border 3 --; break; } } while border 2 <= border 3; and write swap( ). . . }

Sample Question 2 Assume that you have an array, u, of n integers, •

Sample Question 2 Assume that you have an array, u, of n integers, • where no integer appears more than once. u is said to be unimodal if there is some index i (where 0 ≤ i ≤ n-1) such that u[0], …, u[i] is a strictly increasing sequence and u[i], …, u[n-1] is a strictly decreasing sequence. For example, u = 2, 4, 8, 7, 6, 5, 4, 1, 0, -1 is • unimodal, and u = 5, 3, 2, 1 is unimodal, but u = 2, 3, 1, 4 is not.

Sample Question 2 a Write a non-recursive method that • receives an array of

Sample Question 2 a Write a non-recursive method that • receives an array of integers, returns the value of i if the array is unimodal, and returns -1 if the array is not unimodal. Make this method as efficient as you can. What are the big-O best-case and • worst-case complexities of your method? Explain.

/******************************* * Once a unimodal array starts decreasing, it doesn’t increase * @param data

/******************************* * Once a unimodal array starts decreasing, it doesn’t increase * @param data * Possibly unimodal array data[ ] * @return * The location of the array’s single peak, or -1 if the array is not unimodal * Best case: O(1) --- it can discover the first two values are equal * Worst case: O(n) --- it has to run through whole array to check if it's unimodal *******************************/ public static int unimodal. Check (int[ ] data) { int last = data. length - 1, max. Loc = 0; // location of peak boolean falling = false; for (int i = 0; i < last; i++) { if (data[i+1] == data[i]) return -1; if (data[i+1] > data[i]) { if (falling == true) return -1; else max. Loc = i+1; } else falling = true; // data[i] > data[i+1] } return max. Loc; // we get here, it's a unimodal array }

Sample Question 2 b • Now write a non-recursive method that is guaranteed to

Sample Question 2 b • Now write a non-recursive method that is guaranteed to receive a unimodal array of integers, and returns the value of i. Make this method as efficient as you can. • What are the big-O best-case and worst-case complexities of your method? Explain.

/******************************* * A unimodal binary search, checking for a complete peak at each jump.

/******************************* * A unimodal binary search, checking for a complete peak at each jump. * There are no duplicated contiguous entries in the array, by the definition of * unimodal arrays --- and the array is guaranteed unimodal, we're just * looking for the peak * @param data * Guaranteed unimodal array data[ ] * @return * The location of the array’s single peak * Best case: O(1) --- might find peak after first calculation of middle * Worst case: O(log n) --- it might have to collapse the unknown region to a * single array location, before it finds the peak; but the collapsing is done * like binary search, so it cuts the unknown region in half each time *******************************/

public static int unimodal (int[ ] data) { int middle, lower = 0, upper

public static int unimodal (int[ ] data) { int middle, lower = 0, upper = (data. length - 1); do { middle = ((lower + upper) / 2); if (middle == 0) { if (upper == 0) return 0; // array of one element else if (data[middle] > data[middle+1]) return middle; else return (middle+1); } else { if (data[middle] > data[middle+1]) { if (data[middle] > data[middle-1]) return middle; else upper = middle-1; } else lower = middle+1; } } while (lower < upper); // we stop if lower and upper meet // if we get here, data[lower] is the array’s peak return lower; } // unimodal