560 likes | 659 Views
MT-201 Unit 6 : Advanced control structures & squares. A) Complex logical expressions And [ && ], Or [ || ] , Not [ ! ] Short-circuit evaluation of logical expressions Bitwise operators [ & ], [ | ], [ ^ ] B) Advanced branching statements Nested [ if / else ] statement
E N D
MT-201 Unit 6 : Advanced control structures & squares A) Complex logical expressions • And [&&], Or [ || ] , Not [ ! ] • Short-circuit evaluation of logical expressions • Bitwise operators [&], [ | ], [ ^ ] B) Advanced branching statements • Nested [ if / else ] statement • [ break ] in [ switch / case ] statements C) Advanced looping statements D) Sorting (Insertion sort) E) Multidimensional squares F) Recursion — an advanced control structure http://learn.ouhk.edu.hk/~t441063
A) Complex logical expressions • How to express the following formula in Java ? • How about ? • Wrong !? How about adding more brackets ? • Still wrong. Depending on the content in x , it is : • Correct syntax : If ( 0 < x < 100 ) { . . . . . . } If ( (0 < x) < 100 ) { . . . . . . } If ( false < 100 ) { . . . . . . } If ( true < 100 ) { . . . . . . } If ( (x > 0) && ( x < 100 )) { . . . . . . } If ( (0 < x) && ( x< 100 )) { . . . . . . }
The [ && ] operator • in Table 6.1, conditions a and b denotes two conditions with values of either true or false • Each row in the table is a possible combination of values of conditions a and b. • rightmost column is result of conditions a && b. Table 6.1 Truth table of the [ && ]operator
Case-1 : We can treat sub-condition (0 < x ) as a and (x < 100 ) as b The given expression can be visualized in Figure 6.1, where All possible result values of the given expression for variable x are partitioned in three regions Only the blue region can give a value true The other 2 red regions will give a value false (0 < x) (x < 100) -50 -1 0 1 50 99 100 101 150 (0 < x) && ( x< 100 ) (0 < x ) is trueand (x < 100 ) is true So, (0 < x) && ( x < 100 ) will return true (0 < x) is false So, (0 < x) && ( x < 100 ) will returnfalse ( x < 100 ) is false So, (0 < x) && ( x < 100 ) will returnfalse Figure 6.1 A number line with the two values 0 and 100 indicated
(0 < x) (x < 100) -50 -1 0 1 50 99 100 101 150 • from Table 6.1, we can make Table 6.2 with different values of x • Table 6.2 helps you investigate the relationship between the results of sub-conditions and the overall result • It helps you verify whether a condition is properly constructed Table 6.2 Truth table for condition (x > 0) && (x < 100) for various values of x
Case-2 : • Now, the condition is modified. • Table 6.3 with different values of variable x is made as follows (x < 0) (x > 100) -50 -1 0 1 50 99 100 101 150 (x<0) && ( x>100 ) Table 6.3 Truth table for condition (x < 0) && (x > 100) for various values of x
the overall result of (x < 0) && (x > 100) is always false • this condition has problems • as there is no negative value which can greater than 100 • so, if the condition (x < 0) && (x > 100) is used as the condition in a while loop or a for loop, • the loopwillterminateatonce and • the loop body will not be executed at all • However, if a condition that is always true is used as the condition for a loop construct • the loop will repeat forever and • it is an infinite loop • (you’ll see an example soon)
Case-3 : • Now, the condition is modified to be (x < 0) && (x <100), • From Table 6.4, we note that (x <100) seems redundant, and the given expression can be simplified as (x < 0) (x < 100) (x < 0) -50 -1 0 1 50 99 100 101 150 (x<0) && ( x<100 ) Table 6.4 Truth table for condition (x < 0) && (x < 100) for various values of x
The [ || ] operator • In English, we may have "x < 0" or "x > 100". • In Java, it is written as: (x < 0) || (x > 100) • The || operator is the logicalOR operator. The boolean expressions on both sides of the || operator can be true or false, • Table 6.5 lists the result of the || operator Table 6.5 Truth table of the [ || ] operator
Case-1 : • using Table 6.5, different values of variable x is listed in Table 6.6 (x < 0) (x > 100) -50 -1 0 1 50 99 100 101 150 (x<0)|| ( x>100 ) Table 6.6 Truth table for condition (x < 0) || (x > 100) for various values of x
Equivalents codes • Two relational operators, >= and <=, can be written as two subconditions with an || operator. • For example: • The expressions in the left column are simpler and more readable than those in the right column.
Case-2 : • in Table 6.7, the result is always true. • If this expression were used as the condition for an if loop, the action part is always executed (x>0)|| ( x<100 ) Figure 6.7 Truth table for condition (x > 0) || (x < 100) for various values of x (x > 0) (x < 100) -50 -1 0 1 50 99 100 101 150
Operator precedence • relational operators such as { <, >, <=, >= } take precedence over the && operator and the || operator • so, parentheses, that enclose the sub-conditions, are not necessary. eg. ((0 < x) && (x < 100)) • is equivalent to : (0 < x && x < 100) • It is not necessary to enclose the sub-expressions in parentheses, but it is a good programming practice to enclose them because it can make the expression clearer, eg. • if ( (0 < x) && (x < 100) ) { • ...... • }
The exclusive-OR, XOR, operator [ ^ ] • In Java, we write : (a ^ b) • in Mathematics : (a and ~b) or (~a and b) • 有你 無我, 大家 相反 就 true 相 同 就 false 相 反 就 true 相 同 就 false Table 6.5 Truth table of the short-circuited-OR operator [ || ]
The negation, NOT, operator [ ! ] • we can negate a boolean expression result using a negation operator [ ! ] • The type of expression that follows the ! operator must be boolean • eg. Note : • the expression !(x < 0) • is equivalent to x >= 0
Self-Test 6.1 • For variables a, b and c of type int, returns true if c is between the value of a and b. It returns false otherwise, provided that the value of a is less thanorequaltob. • a <= c && c <= b • For variables a and b of type int, returns true if the sign of the product of a and b is non-negative. It returns false otherwise. • a * b >= 0, or !(a >= 0 ^ b >= 0) Note: XOR works much faster than multiplication • For variables a, b, c and d of type int, returns trueif the values of all variables are equal. Otherwise return false • a == b && b == c && c == d
Short-circuit evaluation of logical expressions • Evaluations of [ && ] and [ || ] operators in Java are short-circuit • sub-conditions on both sides of the && and || operators are evaluated from left to right • If sub-condition on left-hand side (the first operand) determines the result of the entire condition, • the sub-condition on its right-hand side (the second operand) is not evaluated • otherwise, evaluate the rest sub-conditions as usual Table 6.1
The || operator features the same short-circuit evaluation • if the first operand (the condition a) of the || operator is true, the overall result must be true. So, no need to evaluate the second operand (condition b) • && short-circuits on false, while || does when true • 如果考試唔記得, 就 derive them from table 6.1 & 6.5 Table 6.5
How short-circuiting works ? if (month==4 || month==6 || month==9 || month==11) { day = 30; } • Consider • the [ && ] and [ || ] operator are left associated, so the above condition can be read as : • if the content of month is 4 , then we have • by short-circuit, month == 6 is skipped, so we have • similarly, month == 9 is skipped, • again, month == 11 is skipped, so the result is true ( ( ( month==4 || month==6 )|| month==9 ) || month==11 ) ( ( ( true || month==6 )|| month==9 ) || month==11) ( (true || month==9 ) || month==11) ( true|| month==11)
Examples • if ((a>0)&&(b>0)) • If a’s value is –1, then the left operand (a > 0) is false. The overall result must be false regardless of (b > 0) • With && operator, Java will not evaluate the expression (b>0) if (a>0) is false. This can improve performance by avioding unnecessary evaluations • if ((a>0)||(b>0)) • If a’s value 1, then the left operand (a>0) is true. The overall result must be true regardless of (b > 0) • With || operator, Java will not evaluate the expression (b>0) if (a>0) is true
Precautions • Be careful when we construct a complex Boolean expression with short-circuit operators. • It is dangerous to import the program logic to other programming languages. Not all programming languages support short-circuit evaluations • Sometimes, the two operands of the operator have to be evaluated, especially the Boolean sub-expressions with side effects. eg. • ((++i >0 ) && (++j>0))
Non Short-Circuit Evaluation • the OR operator [ | ] • similar to the || operator • Unlike the || operator, even the result of the first operand of the | operator is evaluated to be true, the second operand must be evaluated • the AND operator [ & ] • similar to the && operator • Unlike the && operator, even the result of the first operand of the & operator is evaluated to be false, the second operand must be evaluated
Associativity & precedence Relational Increasing Priority Boolean
Bitwise Operators pp-18 • &, | and ^ operators are also known as bitwise operators when operands are integers. • eg 7310 = 9810 = 7310 &9810 = = 6410 7310 = 9810 = 7310 | 9810 = = 10710
B) Advanced branching statements pp-29 • Ternary conditional operator (? : ) • eg • In this example, 0.9 is assigned to discount • Condition ? Value-for-true : value-for-false • public class Ternary { • public static void main ( String args[] ) { • boolean isMember=false; • double discount; • discount= isMember ? 0.8 : 0.9 • System.out.println(discount); • } • } • if (isMmember) { discount = 0.8; } • else { discount=0.9; }
Nested if • General format or • consider the following codes • If the 1st statement is evaluated to be true, • Java still continues the rest 3 statements, because • these 4 statements are independent of each other. • This will waste processing time if ( condition ) { - - - // if part } else { - - - // else part } // suggested style if ( condition ) { - - - // if part } else { - - - // else part } // my current style if ( (age<18) && (gender ==‘M’) ) { boyCount++; } // 1st statement if ( (age<18) && (gender==‘F’) ) { girlCount++; } // <---+\ if ( (age>18) && (gender==‘M’) ) { manCount++;} // >rest if ( (age>18) && (gender==‘F’) ) { ladyCount++;} // <---+/
We can use nested if/else statements to reduce unnecessary condition evaluation : • Now, Java only evaluates the complex boolean expression two times, instead of four times • better performance & easier maintenance • If age is changed to 21, then • the prior version have to change all 4 statements • it is error-prone if you forget to update any 1 of the 4 if (age<18) { // outer IF if (gender ==‘M’) { boyCount++;} // inner IF else {girlCount++;} // inner ELSE } else { if (gender==‘M’) {manCount++;} // inner IF else {ladyCount++;} // inner ELSE }
Fig 6.5 A nested if / else construct pp-32 • In all cases, only 1 of the 4 blocks of statements will be evaluated condition-1 true false condition-2 condition-3 true false true false statement(s) for condition-1 is true condition-2 is true statement(s) for condition-1 is true condition-2 is false statement(s) for condition-1 is false condition-3 is true statement(s) for condition-1 is false condition-3 is false
pp-34~37 • Please use "if … else if … else if … else" to make the program more readable • a better version ( the suggested version is on slide-26 ) if(mark>=90) { grade='A';} // grade is set by only 1 of elseif(mark>=80) {grade='B';} // these 5 statement blocks elseif(mark>=70) {grade='C';} // ( Fig 6.5 has 4 blocks) elseif(mark>=60) {grade='D';} else{ grade='F';} if (mark>=90) { grade='A';} //suggestions : else {if (mark>=80) {grade='B';} // 1). use curly braces else {if (mark>=70) {grade='C';} // 2). indent each blocks else {if (mark>=60) {grade='D';} else { grade='F';} } } }
Dangling-else problem pp-38 • Please note that the else part always associates with the nearest if statement. • Curlybraces can avoid the dangling-else problem • eg. codes-1 will not return true for children • because Java treats codes-1 as codes-2 • // codes-1 • boolean isAccepted = false; • if (age>=18) • if ( gender == 'F' ) • isAccepted = true; • else • isAccepted = true; • // codes-2 • boolean isAccepted = false; • if ( age>=18 ) { • if ( gender == 'F' ) • isAccepted = true; • else • isAccepted = true; • }
public class DaysInMonth2 { public static void main (String args[ ]) { int month = Integer.parseInt(args[0]); int days; if (month == 2) { days = 28; } else if (month == 4 ||month == 6|| month == 9 || month == 11) { days = 30; } else { days = 31; } System.out.println(days); } } public class DaysInMonth { public static void main (String args[ ]) { int month = Integer.parseInt(args[0]); int days; switch (month) { case 2: days = 28; break; case 4: case 6: case 9: case 11: days = 30; break; default: days = 31; break; } System.out.println(days); // 1st stmt } } break in switch/case pp-40 • break statement is usually added to the end of each case statements • causes control to break out of the switch and jump to the 1st statement following the switch statement • Without an explicit break statement, control will flow through subsequent case statements ( eg. case 4, 6 & 9 ) • following is equivalent using nested if/else
placing or not to place break in a switch/case structure gives you greater flexibility 8 boolean variables are declared & initialized as false If form is 4 or 5, all 8 variables are updated to true if form is 3, then 7 variables will be updated to true Otherwise, only the last 4 variables will be updated to true eg, when form is 1 or 2 Note : switch/case is more elegant & easier to read, even though it can be rewritten using if/else boolean takeComputer = false; boolean takePhysics = false; boolean takeChemistry = false; boolean takeBiology = false; boolean takeChinese = false; boolean takeEnglish = false; boolean takeMaths = false; boolean takeMusic = false; switch ( form ) { case 5: case 4: takeComputer = true; case 3: takePhysics = true; takeChemistry = true; takeBiology = true; default: takeChinese = true; takeEnglish = true; takeMaths = true; takeMusic = true; break; }
C) Advanced looping statements pp-42 • Any number of statements can be placed in the loop body of a loop • these statements can include both • branching ( eg. if/else , switch/case ) and • looping ( eg. do/while , while , for ) • the number of levels of nested loops is unrestricted while ( . . . ) { // outer loop - - - - - - - - } for ( . . . ) { // inner loop A } do { - - - - } while ( . . . )
Example: public class Pattern { // Self-test 6.6 pp-110 public static void main(String args[]) { for (int i=0;i<5;i++) { for (int j=0; j<=i; j++) { System.out.print("*"); } System.out.println(" i="+ i"); // start a new line } } } Screen output : • when i=0, inner loop iterates once; so, print 1 "*" • when i=1, inner loop iterates twice; so, print 2 "*"s • when i=2, inner loop iterates 3 times; so, print 3 "*"s • when i=3, inner loop iterates 4 times; so, print 4 "*"s • when i=4, inner loop iterates 5 times; so, print 5 "*"s * i=0 ** i=1 *** i=2 **** i=3 ***** i=4 keep printing on the same line UNLESS it exceed the screen width ensures the next output starts at a new line
refer to codes-1 innerfor loop can access both i and j outerfor loop can only access i but can't access j refer to codes-2 declaring j outside the inner loops, both loops can access both i and j it is not preferable, especially when j is changed in both outer and inner loops, because logic is complicated and the program is more difficult to read & maintain. declare i for outer loop public class Pattern { // codes-1 (self test 6.6) public static void main(String args[]) { for ( int i=0; i<5; i++) { // outer for( intj=0;j<=i;j++) { // inner System.out.print("*"); } System.out.println(" i="+ i"); } } } declare j for inner loop public class Pattern1 { // codes-2 public static void main(String args[]) { for (int i=0; i<5; i++) { int j; for (j=0; j<=i; j++) { j *= 2; System.out.print("*"); } System.out.println(" i="+i+", j="+j); } } } declarej for inner loop j is accessible by outer loop *i=0 j=1 **i=1 j=3 **i=2 j=3 ***i=3 j=7 ***i=4 j=7 Screen output
public class ObjectWithNestedLoop { public void showVariablesInNestedLoop ( int outerLimit, int innerLimit ) { int count = 0; for (int i=0; i < outerLimit; i++) { for (int j=0; j < innerLimit; j++) { count++; System.out.println( count + " : i=" + i + " & j=" + j); } } System.out.println( "Total number of iterations = "+ count ); } } public class TestObjectWithNestedLoop { public static void main(String args[]) { if (args.length < 2) { System.out.println( "Usage: java TestObjectWithNestedLoop" + " <outer limit> <inner limit>"); } else { ObjectWithNestedLoop objectWithNL = new ObjectWithNestedLoop(); int outerLimit=Integer.parseInt(args[0]); int innerLimit=Integer.parseInt(args[1]); objectWithNL.showVariablesInNestedLoop (outerLimit, innerLimit); } } } Revisiting Class & Driver concept pp 45~46
N:\unit-6>java TestObjectWithNestedLoop 3 Usage: java TestObjectWithNestedLoop <outer limit> <inner limit> java TestObjectWithNestedLoop 2 3 1 : i=0 & j=0 2 : i=0 & j=1 3 : i=0 & j=2 4 : i=1 & j=0 5 : i=1 & j=1 6 : i=1 & j=2 Total number of iterations = 6 java TestObjectWithNestedLoop 3 2 1 : i=0 & j=0 2 : i=0 & j=1 3 : i=1 & j=0 4 : i=1 & j=1 5 : i=2 & j=0 6 : i=2 & j=1 Total number of iterations = 6 java TestObjectWithNestedLoop 3 0 Total number of iterations = 0 java TestObjectWithNestedLoop 0 3 Total number of iterations = 0 java TestObjectWithNestedLoop 1 1 1 : i=0 & j=0 Total number of iterations = 1 java TestObjectWithNestedLoop 1 2 1 : i=0 & j=0 2 : i=0 & j=1 Total number of iterations = 2 java TestObjectWithNestedLoop 2 1 1 : i=0 & j=0 2 : i=1 & j=0 Total number of iterations = 2 Testing on " TestObjectWithNestedLoop " ensure each cases are encountered Inner loop was called once & it iterated twice Inner loop was called twice; each time iterated once
Break Vs Continue pp 52 • The break statement, • is usually used in switch/case statements • can be used in the loop body • When break statement is executed, the program control jumps to the statement after the loop body, • i.e. break the loop • The continue statement • the program control • jumps to the end of the loop and then • go back to the condition checking and continues
class ContinueAndBreak { public static void main (String args[]) { int i, max=7; for (i=1; i<=max; i++) { if (i==4) { break; } System.out.println("i = "+i); } System.out.println("break => ends & don't print 4 & others"); for (i=1; i<=max; i++) { if (i==4) { continue; } System.out.println("i = "+i); } System.out.println("continue => skip 4 & resume job"); } } // adopted from Kwan Ying's example i = 1 i = 2 i = 3 break => ends & don't print 4 & others i = 1 i = 2 i = 3 i = 5 i = 6 i = 7 continue => skip 4 & resume job Example Screen Output
D) Sorting pp 59 • Binary search requires the elements must be ordered • such as ascending order of numeric values • Such an ordering operation is known as sorting • For example, if you have an square object with element type of int as follows, • it is expected after sorting, the contents of the square elements have become
Insertion sort 0 sorted pp 61~65 storage unsorted Step1: Separate the sorting scope into 2 regions : sorted, unsorted Step 2: Copy the first element, such as A, of the unsorted region to a variable storage Step 3: Start from the last number of the sorted region, compare with the number in the variable storage . If it is greater than A, then it moves downward. Step 4: Insert the number A to the empty space in the sorted region 32 32 4 sorted 4 4 unsorted 87 sorted unsorted 22 sorted 22 22 unsorted
public class InsertionSorter2 { public static void sort(int[] numbers) { for (int sorted = 0; sorted < numbers.length - 1; sorted++) { System.out.print("DEBUG: sorted region = "); for (int i=0; i <= sorted; i++) { System.out.print(numbers[i] + "\t"); } System.out.print("\nDEBUG: unsorted region = "); for (int i=sorted + 1; i < numbers.length; i++) { System.out.print(numbers[i] + "\t");} System.out.println(); int storage = numbers[sorted + 1]; System.out.println("DEBUG: Number to be moved = " + storage); int forCompare = sorted; while (forCompare >= 0 && numbers[forCompare] > storage) { numbers[forCompare + 1] = numbers[forCompare]; System.out.println("DEBUG: " + numbers[forCompare] + " is copied to the next element"); forCompare--; } numbers[forCompare + 1] = storage; System.out.println("DEBUG: " + storage + " is stored in numbers[" + (forCompare + 1) + "]\n"); } } } pp 71
public class TestInsertionSorter2 { public static void main(String args[]) { if (args.length == 0) { System.out.println( "Usage: java TestInsertionSorter num1 num2 ..."); } else { int[] numbers = new int[args.length]; for (int i=0; i < args.length; i++) { numbers[i] = Integer.parseInt(args[i]) } InsertionSorter2 sorter = new InsertionSorter2(); sorter.sort(numbers); // Sort numbers using square object System.out.println("Sorted numbers:"); // Show the sorted numbers on screen for (int i=0; i < numbers.length; i++) { System.out.print(numbers[i] + "\t"); } System.out.println(); } } }
Screen output • java TestInsertionSorter2 12 32 4 87 22 • DEBUG: sorted region = 12 • DEBUG: unsorted region = 32 4 87 22 • DEBUG: Number to be moved = 32 • DEBUG: 32 is stored in numbers[1] • DEBUG: sorted region = 12 32 • DEBUG: unsorted region = 4 87 22 • DEBUG: Number to be moved = 4 • DEBUG: 32 is copied to the next element • DEBUG: 12 is copied to the next element • DEBUG: 4 is stored in numbers[0] • DEBUG: sorted region = 4 12 32 • DEBUG: unsorted region = 87 22 • DEBUG: Number to be moved = 87 • DEBUG: 87 is stored in numbers[3] • DEBUG: sorted region = 4 12 32 87 • DEBUG: unsorted region = 22 • DEBUG: Number to be moved = 22 • DEBUG: 87 is copied to the next element • DEBUG: 32 is copied to the next element • DEBUG: 22 is stored in numbers[2] • Sorted numbers: • 4 12 22 32 87 pp 72
E) Multidimensional Arrays pp 77 • It is an array of array Objects • Declaration Syntax: • eg. • Alternatively • type[][] <variable> // variation 1 • type <variable>[][] // variation 2 • int [] [] a = new int [5] [10]; • int [] [] a = new int[5][]; • a[0] = new int[10]; • a[1] = new int[10]; • a[2] = new int[10]; • a[3] = new int[10]; • a[4] = new int[10];
Example-1 • double[][] threeByFourTable; • threeByFourTable = new double[3][4]; [0] threeByFourTable [1] [2] 3
square[0] [0] pp 80~83 [0] [1] square[0] [2] 3 square[1] [1] square[0].length [0] square[1] square [1] [2] 3 3 square[2] [0] Example2 square[2] • int [] [] square = { {8,3,4}, {1,5,9}, {6,7,2} }; 3
Matrix Manipulations ( out syllabus ) pp 82 IdentifyMatrix, diagonal elements are all '1's; others are '0' • Given : two 2x2 matrix A and B Addition of A and B Product of Matrix A and B