-
Notifications
You must be signed in to change notification settings - Fork 335
Expand file tree
/
Copy pathalgorithms.org
More file actions
3280 lines (2251 loc) · 133 KB
/
Copy pathalgorithms.org
File metadata and controls
3280 lines (2251 loc) · 133 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
* Data Structures and Java Collections Framework
** Chapter 0 - Introduction to Java
*** Review the fundamentals
Class = fields + methods
main() method called by JVM on starting a new program
Primitive type:
- some values in java and the operations that can be performed on them
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_0.png]]
char c = '\u263A'
in this context, the sequence of symbols starting after the '\' are treated as a single character. the 'u' is for unicode
Classes - custom types, can created by us
- String
*** Use javadoc in writing method specifications
A method specification is the explicit information a user will need in order to write code that invokes a method
*javadoc* - a program that converts Java source code's comments to HTML (Sphynix in python)
multiline comments -
/**
*
*
*/
the javadoc has - @param, @return, @throws
**** Equality of references and equality of objects
the "equals" method compares the *object type*
so, String object 1 == String object 2 (if they contain the same string i.e.)
the "==" operator compares the equality of references
i.e. if the 2 references contain the same address
consider:
String str0="yes";
String str3="yes";
str0==str3 --> true
here, only one String object is created, we say that the String object has been *interned*
but, here:
String str0=new String("yes");
String str3=new String("yes");
str0==str3 --> false
because we are explicitly creating new string objects
#+begin_src java
public class One()
{
public void static main(String[] args)
{
System.out.println("text");
}
}
#+end_src
variables declared within the method (including the mehtod's parameters) are called the local variables
*they must be explicitly initialized before they are used*
scope of the local method can be the entire function or just the "for" loop for eg
/it is illegal to re-declare a local identified within it's block/
*** The Scanner class
it operates on /text/
Scanner sc = new Scanner(<reference from where text is to be read>)
the reference can be:
- System.in
- new File("myFile.dat")
- line - where line is a String object
nextInt - the scanner divides the text into token seperated by delimiters. the nextInt method parses the input, discards the delimiters (space, tab, newline etc) and takes in a token which is an int
hasNext - returns true if there is another token to be read in, false otherwise
hasNextLine - returns true iff there is at least one more char(including delimiters) in the text
nextLine - it advances the scanner past the current line and returns the remainder of the current line (excluding end-of-line marker like \n)
next - skips the whitespace (and other delimiters) and returns the next token
**** Arrays
it is a collection of elements that are stored contiguously in memory
it is of fixed length
int[] eg = {1, 2, 3};
int[] eg; // space created on the stack for the variable eg
eg = new int[4]; // int array object created on heap, address stored in eg variable on stack
*** Passing args
arguments - when a method is called
parameters - in the called method's heading
Java uses pass by copy
a copy of the argument is made and is passed to the function
python is pass by reference, but some objects are immutable so it becomes pass by copy in case of string etc
But there is a catch:
1. the argument is never affected by a method call
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_1.png]]
OUTPUT: 30
Here, the int was passed as argument, it is not affected. the
2. if the argument is a reference
the argument itself will not be affected, but the object referenced by the argument MAY change (it changes if the object is MUTABLE, not OTHERWISE)
so, Arrays are mutable and they can be changed. Scanner is also mutable
String are immutable and they cannot be changed
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_2.png]]
OUTPUT - yes
#+ATTR_ORG: :width 200
#+ATTR_ORG: :height 200
[[./assets/JCF_3.png]]
this is what happens :top:
** Chapter 1 - Object oriented Concepts
*** Data abstraction
When the user of a class does not need to know how the class is implemented(but just focus on how to use it), it is called data abstraction
*Abstract data types* - interfaces
#+begin_src java
public interface Employee
{
String getName(); //empty method which should return string and accept no params
double getGrossPay(); // likewise
final static DecimalFormat MONEY = new DecimalFormat(" $0.00"); // a class constant
}
public class FullTimeEmployee implements Employee
{
private String name; // we can define custom variables for this class
private double grossPay;
public FullTimeEmployee()
{
name = "foo";
grossPay = 1.1;
}
// implement the getName method
// implement the getGrossPay method
}
#+end_src
*this* --> refers to the object
*List* interface - this is implemented by *LinkedList*
*** inheritance
#+begin_src java
public class HourlyEmployee extends FullTimeEmployee
{
// class implementation - make new attributes, new methods, override the parent's methods, overload them
// override - same args + return type
// overload - different args and/or return type. But you cannot have just the return type differ
}
#+end_src
constructors are never inherited
but whenever a subclass constructor is called, the parent's constructor is called first, starting from the constructor of the Object class
to call the custom constructor of the parent class, the first statement of the child's constructor must be:
super(<args>);
Children can take the place of parents - if you expect a reference to parent object somewhere, a reference to subclass object is allowed
this is because the child has same or more methods implemented
Parent foobar = new Child(); // this is allowed
foobar.hello(); //if the Child has this method(it may have overridden it or it might be it's own), that version will be called
So, the version of the method invoked depends on the run-time type of the object being referenced, not on the compile-time type of the reference variable
has-a relationship --> fields in a class
is-a relationship --> inheritance
Encapsulation - hiding the variables from the user and exposing methods to access/set them
this helps enforce the Principle of Data Abstraction, but not exposing the internals of the object to the outside world
*** polymorphism
defined as the ability of a reference to refer to different objects in a class hierarchy
Consider this:
#+ATTR_ORG: :width 600
#+ATTR_ORG: :height 600
[[./assets/JCF_4.png]]
Here, when we call employee.toString(), the method called depends on weather the line contained "full time" or not - this is *polymorphism*
the compiler does not know at compile time which object's method is called, this is determined at run-time(this feature is called *dynamic binding* or *late binding*)
such methods (whose implementation is determined at runtime are called *virtual method*)
in Java, almost all the methods are virtual methods(except static methods and final methods - final means the method cannot be overriden in subclasses). This makes Java program run slower than C.
*** making class diagrams using Unified modeling language
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_5.png]]
the arrow is from subclass to superclass
** Chapter 2 - Additional features of Programming and Java
*** static members and instance members
instance variables are the variables that are associated with the object of the class
static variables are variables that are associated with the class itself - it is shared by all the instances of the class (all the objects)
eg, to count the number of objects of class Student, we can have:
protected static int count=0;
and in the constructor, we can increment the count by 1
constant variables are the variables that are represent a constant, whose value can be assigned only once
eg:
protected final static int SPEED_LIMIT = 65.0; // this value is same for all instances of the class, as it is a static final
constants within a method cannot be declared as static
recall, we read somewhere that the "out" in System.out.prinln(""); is a static, here is it's defination:
public final static PrintStream out = nullPrintStream();
recall static methods are not virtual, they are bound to the classes (method identifiers) at compile time, rather than at run time - since they are associated with the class itself, not to the instance of the class
*** JUnit tests for class's methods
"Testing can reveal the presence of errors, but not the absence of errors"
#+begin_src java
import static org.junit.Assert.*;
@Test
public void toStringTest()
{
FullTimeEmployee full = new FullTimeEmployee("a", 150.00);
String expected = "a $150.00 FULL TIME";
assertEquals(expected, full.toString());
}
#+end_src
The assertEquals method is an overloaded method in the Assert class of the org.junit package
Method signature of assertEquals:
public static void assertEquals (java.lang.Object expected, java.lang.Object actual)
Here, since the method expects objects of Object class, and so by polymorphism, we can pass it any object (since all classes inherit the Object class)
*** try/catch blocks
An /exception/ is an object that is created by an unusual condition. The exception is said to be /thrown/
#+begin_src java
public String rearrange(String fullName)
{
String result;
try
{
Scanner sc = new Scanner(fullName);
}
catch (NoSuchElementException e)
{
// handle the error
}
}
#+end_src
If an exception is thrown in a method that does not catch that exception, control is transferred back to the calling method(the caller of this method AKA the method that called the method that threw the exception)
you mention the exceptions that you method can throw javadoc of the method with @throws <ExceptionName> - <details, summary>
throw it like so:
if (year < SOME_VALUE)
throw new IllegalArgumentExcpetion();
To know the end of input, we can use some value as *sentinel* value, like: EOF, **** etc
Checked exceptions - the exceptions that we know maybe thrown and so we either catch them or propagate it using throws in the method heading
public void sample() throws IOException
The calling method now must either catch the exception or must propagate it using throws in it's name
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_6.png]]
Exception hierarchy
if you put the more general catch statement before the more specific catch statement, the compiler will say it is an error as the 2nd catch is unreachable code
There is a *finally* block after the last catch block that will b executed weather or not any exceptions were thrown in the try block
*** JVM
The Java code is compiled to JVM bytecode which is then run (interpreted) by JVM
(this is *exactly* what happens in python as well, the python code is converted to python bytecode which is then run by the python interpreter which is a C program. Here too, the JVM is a C program(or can be implemented in any other language as well - it is just a specification)
The benefits - platform independence - since the source code is not converted to machine code directly, the code will run on any platform that can run the JVM (which is C)
also, there is additional security since the bytecode is not run on bare metal, but in the JVM - so the JVM can choose to not allow the application to read from/write to the local disk etc
The JVM oversees all aspects of your program's run-time environment.
The JVM has 3 main tasks:
_1. Pre-initialization of fields_
Initialization of fields just prior to the invocation of a constructor
i.e. when the constructor is called to create a new object, the JVM is responsible for allocating space for the object, initialize the variables of the new object(either with the values provided to the constructor or with default values - int gets 0 etc), and return the address of the new object
*Note* : only the fields of the class get initialized, local variables (defined inside the methods) don't
_2.Garbage collection_
When there are no living references to an object, and when the JVM needs space to allocate for new objects, the old unreferenced objects will be garbage collected
_3. Managing threads_
starting and managing threads etc.
*** Override Object class's equals method
The Object class has a method "equals"
here is the defination:
public boolean equals(Object obj)
{
return this == obj;
}
now, in your own class, you can create your own equals method if you want to. 2 ways - overload the Object classes equals or override it
Overload:
public boolean equals(FullTimeEmployee full)
:top: yes, this is overloading - since the args are different
Override:
public booean equals(Object obj)
//diff code
the default equals compares references, we can change that:
public boolean equals (FullTimeEmployee full)
{
return name.equals(full.name) "" Money.format(grossPay).equals(Money.format(full.grossPay));;
} // overloading the method
The *instanceof* operator returns true iff at run-time, the object referenced by the left operand is an instance of the class that is the right operand
*** packages and visibility modifiers
A package is a collection of related classes
for each such class, the file in which the class is declared starts with the package declaration
package neuralNetwork;
eg: the Scanner class is a part of the java.util package
so:
package java.util;
*Each java file must have a one and only one class with the visibility modifier public*
other classes can have default visibility.
also, the name of that public class must be the same as the name of the file
java.lang is imported by default
A class with no visibility modifier has the *default visibility* - which is that the class can be accessed by any object in the same package as the class in which the member is declared
*protected* -- if an identifier (can be a variable, method etc) in a class has protected visibility, that identifier can be accessed in any class that is in the same package as the given class. Also, it can be accessed in any subclass of the given class, even if it is in a different package
/*protected* is even less restricted than default visibility/
rule of thumb - use private for fields, and public for the getter and setter methods
** Chapter 3 - Analysis of Algorithms
*** Big-O notation
For an implementation, we can define the
worstTime(n) -- where n is the input size or
averageTime(n) --> where we can assume all input possibilities(favorable - best case and unfavorable - worst case) of size n
Same for space - worstSpace(n) and averageSpace(n)
Big-O --> gives us an idea of the /upper-bound/ for the behavior of the algo
When we say that :
BigO(f) = g
we meanL
C.f(n) >= g(n) for all n>=K
that is, let the constant C be sufficiently large, for sufficiently large input size(n), the function g will be smaller than function f
i.e. g is the upper bound of f
Since Big-O is an upper bound, if there is a function f(n) = 4*n+2, it has O(n), O(n^2) ... etc
#+ATTR_ORG: :width 800
#+ATTR_ORG: :height 400
[[./assets/JCF_7.png]]
BigO can be misleading if the value of *n* is small:
#+ATTR_ORG: :width 800
#+ATTR_ORG: :height 400
[[./assets/JCF_.png]]
**** Common BigO functions
***** Log n
#+begin_src C
#include <stdio.h>
int main()
{
while (n>1)
n=n/2;
print(n);
}
#+end_src
(or something similar to start with i=1, i*=2 till i<n) is *log n*
In general - if during each loop iteration, n is divided (or multiplied) by some constant greater than 1, worstTime(n) will be O(logn) for that loop
Binary search has running time of logN because in each iteration, half the input is discarded and the total times the loop runs is logN
***** O(n)
for (int i = 0; i<n; i++)
print(i)
this is O(n)
passing thru the input once, for eg to search in an unsorted array is O(n)
***** O(nlogn)
for (int i=0; i<n; i++)
while (j>1)
j/=2;
print j;
this is logn + logn + ... + logn --> n times, so, nlogn
This is the running time of several sorting algos
***** O(n^2)
for (i=0; i<n;i++)
for (j=0;j<n;j++)
print(i, j)
this is:
n + n + n + ... + n
:top: is n times, so n*n = n^2
Consider this:
for (i=0; i<n;i++)
for (j=i;j<n;j++)
print(i, j)
n + (n-1) + (n-2) + ... 1
which is n(n+1)/2 --> O(n^2)
Selection sort uses this
*** big-omega
BigO provides the upper bound - BigOmega provides the lower bound
let f,g be a function, then: g is BigOmega(f) iff:
g(n) >= C.f(n) for all n>K ((for sufficiently large n)) -- C,K are constants
i.e., however large a constant you give to g(n), for sufficiently large values of n, f(n) will be larger
eg:
f(n) = 2n^2 + 3n
f = BigOmega(n^2), BigOmega(n), BigOmega(1) etc
i.e. to say, if we have BigOmega(n^2), it is a subset of BigOmega(n), which is a subset of BigOmega(1) etc
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_8.png]]
*** big-theta
let f be a function, then we can say it is BigTheta(g) iff:
C1.g(n) <= f(n) <= C2.g(n) for constants C1, C2 with C2>C1 and n sufficiently large (or, for all n>k)
that is, f(n) is exactly bound by g(n)
*saying that is function f is BigTheta(g) is exactly the same as saying it is BigO(g) AND BigOmega(g)*
#+ATTR_ORG: :width 800
#+ATTR_ORG: :height 400
[[./assets/JCF_9.png]]
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_10.png]]
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_11.png]]
Polynomial time problems - O(n^i) where i is some integer >=2
:top: they are bad, but not worse than exponential time which are O(i^n) for i>=2
such problems, whose solving compulsarily requires exponential steps(there is no other way to solve them that would require smaller steps) are called *intractable* problems - eg, travelling salesman problem, printing to 2^n
Consider:
f(n) = n + n/2 + n/4 + ...
this is BigO(n) because:
n(1+1/2+1/4+...) = n(some const) = n
do not confuse this with logn running time,
there, we do constant work, logn times - i.e. 1+1+1+... logn times, so, logn
but, if we did n work logn times, it would be nlogn etc
Basically, just make a series and sum it up
** Chapter 4 - The Java Collections Framework
The JCF is an assortment of interfaces and classes which implement those interfaces. They are a part of the java.util package
Most of the classes of JCF are instances of a collection - i.e. each instance is composed of collections of elements.
Java has recently introduced type parameters to specify the type of the elements when declaring an instance of a collection class
*** What is a collection
A collection is an object that is composed of elements
the elements can either by primitive (ints) or references to objects
eg:
Array - collection of elements of same type, stored contiguously in memory (in reality, it may or may not be stored continuously, what matters is that it can be accessed with it's index)
String[] names = new String[5];
here, :top: JVM creates allocates space for an array of 5 String references and returns a reference to the beginning of the space allocated, the reference is stored in reference variable names
Arrays support random access since they are contiguous
drawbacks
- fixed size
- space for the entire array must be allocated before any elements can be stored in the array
- if you want to insert something at index 300 of an array with 1000 elements (and indexes upto 800 filled), then the elements 300-800 will have to be shifted by one place
Better alternatives: instances of collection classes
*collection class* - a class in which each instance is a collection of elements and each elements is a reference to an object. this means that we cannot create an instance of a collection class with primitives in it, we will have to first wrap them in wrapper classes (eg, Integer for int) before we can put them in the collections class
#+ATTR_ORG: :width 600
#+ATTR_ORG: :height 400
[[./assets/JCF_12.png]]
Each member of the collections class has an isEmpty method
There are 2 types of collections classes in terms of how they store the elements
1. contiguous-collections
for eg, ArrayList
2. linked-collections
here, the elements are housed in a special entry called nodes and they are linked by storing a reference to each the next one within them
#+ATTR_ORG: :width 800
#+ATTR_ORG: :height 400
[[./assets/JCF_13.png]]
The JCF consists of a thoroughly tested assortment of interfaces and classes.
the classes represent widely used data structures and algorithms
The JCF is huge, there are over 200 methods in 8 classes (which we will study)
The Interfaces and Abstract Classes present in the JCF are unifying tools, they force method headings on the implementing classes.
Recall - an Abstract Class is a class with at least one (or all) abstract method. I.e. the method has a body, need not be empty (like in the interface) but it is marked abstract. The subclass extending this abstract class can override the method or mark it as abstract and let it's children override it.
Some abstract classes in JCF - AbstractCollection, AbstractList, AbstractSet
Some points:
- an interface can extend one or more interfaces (public interface Container extends Collection, Comparable)
- a class can implement one or more interfaces (class NewClass implements Interface1, Interface2)
- A class can extend and implement interfaces both (class NewClass extends OldClass implements Interface1, Interface2)
Since J2SE, (i.e. Java 2 Platform, Standard Edition), you can define in angle brackets, the class's element type which it is meant to store
ArrayList<Double> ald = new ArrayList<Double>();
add elements with ald.add(new Double(2.2)) -- this will add to the end of the arraylist
get elements - Double gpa = ald.get(index);
Double wrapper class -> double value:
- gpa.doubleValue();
This feature to mention the type of the references (elements) that are to be stored in the Collections class is called "generics"
in the example above, :top: ArrayList<Double> is a parameterized type, AKA "generic type"
Parameterized types improve your productivity as a programmer, this is because you don't need to check if the element is of a certain type, you can be assured that it is. Also, you will be prevented from making mistakes if you try to enter someother element type in the Collection class.
Auto-boxing - since the Collections classes cannot store primitives, and can only store references to objects, Java supports auto-boxing, i.e. if you try to store ald.add(1.1), it won't throw an error, it will wrap the primitive in it's wrapper class(Double here) and then store it. Likewise, it will debox it when you use .get() to extract the element
*** Create collections
The Collection Interface consists of a hierarchy. At the bottom are the implementations of the interfaces and extensions of abstract classes.
At the top of the hierarchy, there are 2 interfaces:
*Collection* and *Map*
In the javadocs, the ArrayList (and in the figure below), the *E* is for "element" - as the *type parameter*, it is replaced with an actual class such as Double, FullTimeEmployee etc.
#+ATTR_ORG: :width 600
#+ATTR_ORG: :height 400
[[./assets/JCF_14.png]]
*** Collection interface
"According to the Principle of Data Abstraction, user's code should not access the implementation details of a Collection class"
*Iterators* - objects that allow the elements of Collection objects to be accesses in a consistent way without accessing the fields of the Collection class.
Inside each class that implements the Collection interface, there is an iterator class (nested?) that allows a user to access each element in the collection.
The iterator class itself implements the Iterator interface - which provides the methods: hasNext(), next(), remove()
Here is how to create an iterator object:
Iterator<String> itr = myCollection.iterator();
now, when we call itr.hasNext(), by polymorphism(the method invoked depends on the type of the referenced object and not on the type of the reference variable), myCollection's iterator's hasNext will be invoked.
Example usage:
String word;
while(itr.hasNext())
{
word = itr.next();
if (word.charAt(0) == 'a'):
System.out.println(word);
}
shortcut:
for (String word: myCollection)
{
if (word:charAt(0) == 'a')
System.out.println(word);
}
The second method is exactly the same as the first, the enhanced forloop creates an iterator, and the code is more readable.
# Define multiple variables in the same line:
# int A=1, B=2, C=3;
This makes for clean code:
consider you have to find averages of some numbers, sentinel value is -1
#+begin_src java
final int SENTINEL = -1;
Scanner sc = new Scanner(System.in);
ArrayList<Integer> gpaList = new ArrayList<Integer>();
while (true)
{
in = sc.nextInt();
if (in==SENTINEL)
break;
gpaList.add(in)
}
int sum = 0;
for (int e: gpaList)
sum+=e;
System.out.println(""+sum/gpaList.size());
#+end_src
*enhanced for loop cannot be used if you want to modify the elements of the collection during iteration, eg, if you want to delete from gpaList, if the gradepoint is below 1.0, use iterator*
Iterator<Integer> itr = gpaList.iterator();
while (itr.hasNext())
if (itr.next()<1)
itr.remove();
Appreciate how we used the *iterator pattern* to solve the problem of allowing users of the Collection classes to loop thru the elements without violating the principle of DA (i.e. without them knowing the internals of the class)
*** The List interface
JCF's List interface extends the Collection interface by providing some index-related methods like *get* to get an element at a given index.
The List is an interface which embodies the idea of a data structure which stores elements according to an index (may or may not be contigous)
In the JCF, the List interface is partially implemented by the abstract class AbstractList and the rest by it's subclasses ArrayList and LinkedList
#+ATTR_ORG: :width 600
#+ATTR_ORG: :height 400
[[./assets/JCF_15.png]]
*what is the difference b/w Arrays, Lists, Vectors?* - OQ
So, Lists are just a collection of elements that may or may not be contiguous.
Array are a more specific than lists are refer to collection of elements that are necessarily contiguous
*** Compare LinkedList, ArrayList
The ArrayList class implements the List interface with an underlying Array (contigous)
The LinkedList class implements the List interface with an underlying linked structure (non-contigous)
The Stack class also implements the AbstractList with an underlying Array
So, you can do:
List<Integer> myList = new ArrayList<Integer>();
API:
- myList.add(1);
- System.out.println(myList); // this is equivalent to System.out.println(myList.toString());
the toString method of each Collection class in JCF has overriden the Object class's toString method and returns a String representation of the class.
- myList.contains(22);
- myList.remove(<index>);
- myList.add(<index>, <int element>); // this will move all the elements after <index> to <index+1>
- Iterator<Integer> itr = myList.iterator();
To use LinkedList instead, we could have just replace ArrayList with LinkedList in the line above :top:
Had we used that, the myList.get(5) would be slower in the LL compared to AL because we would have had to traverse all the elements.
But, the myList.remove(<index>) would be faster because we don't have to copy over all the elements after <index> in the LL, we just have to re-wire some elements is all.
*** Summary
#+ATTR_ORG: :width 700
#+ATTR_ORG: :height 400
[[./assets/JCF_16.png]]
** Chapter 5 - Recursion
*** Where is recursion useful?
Recusive methods - methods that call itself, *with a terminating condition*
Note: Officially, a method must be termed *static* if it depends only on it's parameters (arguments passed to it) and not on the instance variables. This is there, but additionally, a *static* method must also not modify the state variables - In Java, the compiler won't let it, but still; Good to know.
Consider the classical factorial program:
public static long factorial(int n)
return fact(n)
protected static int long fact(int n)
if n<=1 return 1;
return n*fact(n-1);
here, fact is recursive, not factorial
The factorial method is just a wrapper for the fact method
When we do fact(3), it goes like this:
3*fact(2) // at this point, the value of 3 must be saved somehow, also of n
2*fact(1)
2*1
3*2
6
*** how do recursive methods get executed
We can study the recursive methods by using *execution frames*
make boxes with information values of parameters and other local variables
make arrows to represent return values
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_17.png]]
*Any problem that can be solved recursively can also be solved iteratively*
Iterative method uses loops.
*** compare recursive and iterative methods wrt space and time and ease
Weather to use iterative or recursive methods depends on the type of the problem and the tradeoff related to ease of solving it(ease of converting from recursive->iterative), space and time requirements.
For the factorial, using a simple loop is simple enough and we don't have to pay the extra space cost
but consider the problem of converting int to binary
**** int to binary
if we solve the problem with this observation:
The rightmost bit has the value of n%2; the rest of the bits are the binary equivalent of n/2;
example:
#+ATTR_ORG: :width 600
#+ATTR_ORG: :height 400
[[./assets/JCF_18.png]]
Here, the recursive solution:
we will return the binary in String format
public static String intToBinary(int num)
return getBin(num)
public static String getBin(int num)
if num<=1 return Integer.toString(num);
return getBin(num/2) + Integer.toString(num%2);
*The space and time complexity of recursive calls is dependent on the number of recursive calls*
Here, there are logN recursive calls. In each call, constant work done
so, time - O(logN)
Also, in each call, space required is constant (one char)
so, space - O(logN)
**** towers of hanoi
the problem is simple: we have 3 poles, A B C
There are some disks on pole A to start with, we have to shift them all to pole B using pole C as temporary storage
the rules:
- only one disk may be moved at a time (the top disk of any pole)
- bigger disk cannot be placed on top of smaller disk
Starting position:
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_19.png]]
To solve this, consider how the last disk, disk 4 will be moved to pole B
for that, we need to have:
#+ATTR_ORG: :width 400
#+ATTR_ORG: :height 400
[[./assets/JCF_20.png]]
So, now the problem is reduced from:
move "n" disks from A to B
To
move "n-1" disks from A to C + move disk 4 to B + move "n-1" disks from C to A
This is a recursive definition, we can write:
#+begin_src java
public String solveHanoi(int n, char from, char to, char temp)
{
return recurseHanoi(n, from, to, temp);
}
public String recurseHanoi(int n, char from, char to, char temp)
{
if (n==1)
return "Move top disk from %s to %s" % (from, to);
return recurseHanoi(n-1, from, temp, to) + "Move top disk from %s to %s" %(from, to) + recurseHanoi(n-1, temp, to, from);
}
#+end_src
SO, the recursive strategy works best if you can reduce your problem into a slightly smaller problem which is *exactly* like the original one with a terminal condition
**** searching an array
we can search an array for an item. if the array is unsorted, we have to use linear time sequential search to find if an element is present in the array or not. (return -1 if not, else the index)
If the array is sorted, we can use the binary search which is O(logn)
***** sequential search
a general method that takes in a list to be checked and an item, returns index or -1
We assume that the element class implements the Comparable interface (in java.lang)
Comparable interface just has one method - public int compareTo(T obj)
which returns >0 int if the calling object is > obj, 0 if they are equal or <0 if obj>calling obj
eg: String implements the Comparable interface - so, we can do:
String s = "dadsd";
s.compareTo("ddddd"); --> this will return an int less than int because the calling obj is greater
#+begin_src java
public static int sequentialSearch(Object[] a, Object key)
{
for (int i=0; i<a.length; i++)
if ( ((Comparable) a[i])).compareTo(key) == 0)
return i;
return -1;
}
#+end_src
since we need to use the compareTo function, we need to type cast the elements of list "a" from Object to any type that implements the Comparable interface - so we can call the compareTo method. We cannot if the object belongs to the Object class.
***** binary search
assuming the array is sorted:
#+begin_src java
public static int binarySearch(Object[] a, Object key)
{
return recurseBinary(a, key, 0, a.length);
}
public static int recurseBinary(Object[] a, Object key, int left, int right)
{
int index = left+right/2;
if left==right return -1;
if (a[index]) == key return index;
if (a[index]<key) right=index;
if (a[index]>key) left=index;
return recurseBinary(a, key, 0);
}
#+end_src
*** understanding the backtracking design pattern
Backtracking is natural if one uses DFS or BFS.
Use DFS if you need a yes/no - i.e. if it is possible to reach the destination from the start position or not and you don't care about the optimal path - still need to maintain a mask of nodes you visited
use BFS if you care about the optimal path.
Both DFS and BFS are exponential O(b^m), b is branching factor b, m levels deep
DFS space - O(bm) - draw a stack and pop first element, replace by b children, pop first and replace by b children etc
BFS space - O(b^m) - draw a stack and replace each element by b children, repeat for all elements
DFS is not optimal
BFS is optimal if the cost of each hop is uniform
if it is not uniform, use UCS - uniform cost search which uses a heap and pops according to cumulative score
The problem with UCS is that it has no sense of direction of goal, it explores everywhere uniformly - leads to wastage.
Use a heuristic to get an estimate of direction of goal.
If you follow just the heuristic, you get Greedy search
If you use heuristic+cumulative cost, you get A* which is optimal, complete and expands in the direction of the goal, thus avoiding waste.
BUT, note that the heuristic must be admissible (must be lower than the god-sent truth) and also it must be consistent(difference in heuristic b/w 2 nodes must be LESS THAN OR EQUAL to the cost of that hop) - the latter is a stronger condition
*** The cost of recursion
Everytime a method calls itself (or any other method for that matter), a certain amount of information is saved, this information collectively is called *activation record* (it is just an execution frame) because it pertains to the execution state of the method that is active during the call.
It contains:
- *the return address* - the address of the statement that will be executed when the call has been completed
- *the value of each argument* - java is call by value, so the variables are copied over(if they are primitive) or the references are copied over if they are references. (note, if the references point to immutable objects, they aren't changed, else they are)
- *the local variables* - declared within the body of the called method
This is the main overhead in recursion over the iterative version, (considering space and time complexity to be same)