Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
8 views

Programming in Java - Data Structures - Array ArrayList LinkedList

Uploaded by

die.lolol.1.0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

Programming in Java - Data Structures - Array ArrayList LinkedList

Uploaded by

die.lolol.1.0
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Programming in Java

Data structures: Collections 1


(Array)
ArrayList
LinkedList
An opening caveat
The discussion contained in these slides is a very simplified description of how
variables, arrays, collections, and their representation in memory, work, in the
context of Java programs.
The purpose is to convey the important data structure concepts as clearly as
possible, but not to be comprehensive or absolutely accurate with regard to their
implementation in Java. These data structure concepts are fundamental in
computer science. It is essential to understand them well. The precise details of
how they work in any specific programming language are relatively unimportant.
Consequently, here some details pertaining to Java, specifically, are intentionally
hidden, blurred or even conflated, particularly those regarding references, the
heap, the stack and memory management. A detailed and precise discussion of
such concepts falls well beyond the scope of the IB DP Computer Science
programme.
A simple memory HEXADECIMAL form
BINARY form 0 1 2 3 4 5 6
MEMORY
7 8 9 A B C D E F
00
Consider the small section of computer B:0000 = 0
memory (specifically, Random Access B:0001 = 1
Memory, or RAM), to the right. 2B 2C
B:0010 = 2
In Java, it would be a section of the
B:0011 = 3
memory assigned to the running program,
containing the stack and the heap of the B:0100 = 4
program. (Here we will ignore the fact that a B:0101 = 5
program can have multiple stacks.)
B:0110 = 6
Each square represents a memory location
(or address) that contains one byte (8 B:0111 = 7
bits). The section of RAM shown has 256 B:1000 = 8
(=16×16) locations (from 00 to FF).
B:1001 = 9
Thus, each address in this section of RAM
B:1010 = A
can be specified with 8 bits (28 = 256).
Since one hexadecimal digit can be B:1011 = B
represented with 4 bits (24 = 16), each B:1100 = C
address in this small memory section can B:1101 = D
be represented with 2 hexadecimal digits.
B:1110 = E
FF
B:1111 = F
Locations 00 to 2B (shown in green) are HEXADECIMAL form MEMORY
the part of memory called the stack. BINARY form 0 1 2 3 4 5 6 7 8 9 A B C D E F
00
The stack contains: B:0000 = 0 Oversimplifying, let’s assume all the
• Our declared variables, including their references to the variables declared in
B:0001 = 1 our program are located somewhere in
values if they are of a primitive type 2B 2C
B:0010 = 2 this green area of memory (the stack).
(int, double, boolean, char, …).
B:0011 = 3
• References (also called pointers) to all
other variables: Strings, arrays and B:0100 = 4
objects (instances of classes). B:0101 = 5
But what is a reference? Each reference
is a memory address where the value of B:0110 = 6
the variable is stored (the address is B:0111 = 7
that of the first byte of the value). B:1000 = 8
References point to memory addresses in B:1001 = 9
another area of memory, called the heap.
B:1010 = A
The blue memory locations in the figure
(locations 2C to FF) are the heap. (In a real B:1011 = B
system, the stack and the heap are not typically B:1100 = C
adjacent in memory, as the figure might suggest.)
B:1101 = D
The values of our strings, arrays and
objects are stored in the heap (but their B:1110 = E
FF
references are kept in the stack!). B:1111 = F
Arrays HEXADECIMAL form
BINARY form 0 1 2 3 4 5 6
MEMORY
7 8 9 A B C D E F
We now create an array, nums, of 8 B:0000 = 0 00

numbers of type byte (whole numbers


B:0001 = 1
whose values may range from -128 to 127).
2B
B:0010 = 2
byte[] nums = {23, 42, -12, 96, 54, 39, 54, 33};
B:0011 = 3
Each value of type byte (which appears in B:0100 = 4
the code and in the figure in denary (base-10)
B:0101 = 5
form) can be uniquely specified by a
combination of 8 bits. B:0110 = 6
B:0111 = 7
In other words, each value of type byte
fits in a single byte of memory. B:1000 = 8
The 8 array elements are thus B:1001 = 9
automatically placed in contiguous B:1010 = A 23 42 -12 96 54 39 54 33
memory locations (in the heap), in this B:1011 = B
example from A2 to A9.
B:1100 = C
B:1101 = D
B:1110 = E
FF
B:1111 = F
Arrays HEXADECIMAL form MEMORY
BINARY form 0 1 2 3 4 5 6 7 8 9 A B C D E F
The reference Java associates with our
00
array identifier, nums, includes: B:0000 = 0 id[“nums”] → byte[8]@A2
• The type of values it holds (in this B:0001 = 1 The reference is kept in the stack. The
case, byte). most important part is the address (A2). 2B
B:0010 = 2
• The memory address (in the heap) of B:0011 = 3
its first element (A2).
B:0100 = 4
• The length (i.e., the number of
elements) of the array (8). B:0101 = 5
The compiler will summarise this B:0110 = 6
information as: B:0111 = 7
B:1000 = 8
Our variable
Length of
identifier B:1001 = 9
the array
(name)
B:1010 = A 23 42 -12 96 54 39 54 33
B:1011 = B
id[“nums”] → byte[8]@A2 C
B:1100 =
Memory B:1101 = D
Type of the
address at B:1110 = E
values held
which the FF
in the array B:1111 = F
array starts
Arrays HEXADECIMAL form MEMORY
BINARY form 0 1 2 3 4 5 6 7 8 9 A B C D E F
Accessing any element in the array is
00
easy, and it takes constant time. This B:0000 = 0 id[“nums”] → byte[8]@A2
means that the time it takes does not
B:0001 = 1
depend on the length of the array or on 2B
the position of the desired element in it. B:0010 = 2
B:0011 = 3
For instance, to obtain element 2 of
nums, Java knows it simply has to read B:0100 = 4
the data written in the memory location B:0101 = 5
A2 + 2 (which is A4). (In our ongoing
B:0110 = 6
example, it would read the -12).
B:0111 = 7
Writing data at any position in the array
is just as easy. The assignment: B:1000 = 8
B:1001 = 9
nums[5] = 67;
B:1010 = A 67 54 33
23 42 -12 96 54 39
is resolved by writing the value 67 B:1011 = B
in memory location A2 + 5 (= A7).
B:1100 = C
B:1101 = D
B:1110 = E
FF
B:1111 = F
Arrays HEXADECIMAL form
2 3 6
MEMORY
7 8 9 A B C D E F
The previous method to access and write array
BINARY form 0 1 4 5
00
elements worked because each element was of B:0000 = 0 id[“nums”] → int[8]@A2
type byte, so its size in memory is 1 byte (8
bits). B:0001 = 1 Notice the data type is now int
2B
If nums had been created as an array of 8 B:0010 = 2
values of type int, which can be much larger B:0011 = 3
and need 4 bytes to be specified, each element
in the array would occupy 4 consecutive bytes B:0100 = 4
in memory.
B:0101 = 5
int[] nums = {23, 42, -12, 96, 54, 39, 54, 33}; B:0110 = 6
In turn, the 8 array elements are placed B:0111 = 7
contiguously in memory, each taking up 4 bytes B:1000 = 8
of space. (In this example, from A2 to C1).
B:1001 = 9
Now, to access and/or write elements in this B:1010 = A A2
23
A6
42
AA
-12
AE

array, Java will need to multiply the index of the B2 B6 BA BE


element by the size of the elements. B:1011 = B 96 54 39 54
For int, the size is 4 bytes. B:1100 = C 33
So, to access (or write to) element nums[2], B:1101 = D
Java must read (or write to) the 4 bytes starting
at memory position A2 + 4 * 2 (= AA). B:1110 = E
FF
B:1111 = F
Arrays
Let us return to the array example with values of type byte.

byte[] nums = {23, 42, -12, 96, 54, 39, 54, 33};

When an array is created, we can reassign the values of its elements,


but we cannot add or remove elements from it.
An 8-element array will always have 8 elements, no more, no less.

If we wish to add further elements, we have to:


• create a new, larger array,
• copy into it the values in the original one,
• and then assign each new value to one of the remaining elements
(see next slide).
Arrays 0 1 2 3 4 5 6
MEMORY
7 8 9 A B C D E F
Adding an extra element by creating a larger array, copying
into it the values in the original one, and then assigning the 0 00

new value (say, 124) to the “next available” element would id[“nums”] → byte[8]@A2
look like this in code: 1
id[“nums2”] → byte[16]@64 2B
// Extra element we want to append to the array: 2
Reference to new array, nums2
byte newNum = 124; 3
// Create new array that can fit the extra element:
byte[] nums2 = new byte[16]; 4
// Loop to copy all the values 5
// from the old array into the new one:
for (int i=0; i < nums.length; i = i+1) { 6 23 42
0 42
23 -12
0 -12 96
0 96
0 54 0 54
0 39 0 33 0 0
0 124 0 0
nums2[i] = nums[i]; 7 0 0 0 0
}
// Copy the extra value into the next "available" element: 8
nums2[nums.length] = newNum; 9
// If we want to print out the new array: A 23 42
23 42 -12 96 54 39 54 33
-12 96
System.out.println(Arrays.toString(nums2)); B
The console output is: C
[23, 42, -12, 96, 54, 39, 54, 33, 124, 0, 0, 0, 0, 0, 0, 0]
D
(Numerical arrays are created with 0s as default values.)
E
FF
The figure shows what happens in memory F
Arrays 0 1 2 3 4 5 6
MEMORY
7 8 9 A B C D E F
Once we’ve created the larger array with extra room, it can
fit more values. Suppose we now wish to add an extra value 0 00

in the middle of the array.


For example, let’s add the value 67 in index position 5: 1
2B
nums2[5] = 67;
2
3
The content of the array nums2 after this assignment is:
4
[23, 42, -12, 96, 54, 67, 54, 33, 124, 0, 0, 0, 0, 0, 0, 0]
5
The old value at nums2[5], which was 39, has been 6 23 42
0 42
23 -12
0 -12 96
0 96
0 54 67
0 54
0 39 0 33 0 0
0 124 0 0
overwritten with the new one, 67.
7 0 0 0 0
8
9
A 23 42
23 42 -12 96 54 39 54 33
-12 96
B
C
D
E
FF
F
Arrays 0 1 2 3 4 5 6
MEMORY
7 8 9 A B C D E F
If we did not wish to overwrite the old value, but slot 00
the new one in the index position occupied by the 0
old one, shifting the latter and all the following ones 1
one position to the right, we would have to rewrite 2B
2
all of these positions (starting from the last one, to
avoid losing data due to overwrites), to make room 3
for the new element at the desired position: 4
// Shift values from nums2[5] one position to the right 5
// to make room for new value at nums2[5]:
for (int i = nums2.length - 1; i > 5 ; i = i-1) { 6 23 42
0 42
23 -12
0 -12 96
0 96
0 54 39
0 67 54
0 33
0 39
67 0 124
0 124
54 33 0 0 0
nums2[i] = nums2[i - 1]; 7 0 0 0 0
}
// Assign the new value to nums2[5]: 8
nums2[5] = 67; 9

// If we want to print out the new array: A


System.out.println(Arrays.toString(nums2)); B
The console output is: C
[23, 42, -12, 96, 54, 67, 39, 54, 33, 124, 0, 0, 0, 0, 0, 0] D
E
FF
The figure shows what happens in memory F
Linked lists: the concept
A linked list is a data structure that can store a collection of items.
Like arrays, linked lists are used to store several objects of the same
type. However, linked lists differ from arrays in the following ways:
• Linked lists are dynamically sized; they grow and shrink as nodes
are added and removed and they do not require more memory
than there are objects currently in the collection. Diagram of a linked list:
• The nodes of a linked list need not be stored contiguously in
memory.
• Linked lists are not random-access data structures; items are
accessed sequentially, starting from the beginning of the list.
Each element of the list is referred to as a node. Each node has two
parts:
a) an Object that represents the data stored in the node,
b) a reference to the next node in the list (or the special value
NULL, if it is the last node). We can say that each node “points
to” a next node.
Linked list objects contain a reference to the first node in the list,
called the head. They may also have a reference to the last node,
called the tail. Source: https://www.cs.usfca.edu/~srollins/courses/cs112-
f07/web/notes/linkedlists.html
Arrays vs. Linked lists

Node
Linked lists HEXADECIMAL form MEMORY
BINARY form 0 1 2 3 4 5 6 7 8 9 A B C D E F
The reference Java associates with a
00
linked list identifier, llNums, includes: B:0000 = 0 id[“llNums”] → <byte>@A2
• The type of values it holds (in this B:0001 = 1 The reference is kept in the stack. The
case, byte). most important part is the address (A2). 2B
B:0010 = 2
• The memory address (in the heap) of B:0011 = 3
its first element (A2). This element is
the value of the first node of the list, B:0100 = 4 54 @CD
called the head. B:0101 = 5
Now each node has two parts: B:0110 = 6 -12 @87
• A value (of the specified type for the B:0111 = 7 42 @66
list; in this case, byte). B:1000 = 8 96 @A6
• A reference (memory address) to the B:1001 = 9
next node in the linked list. (For the
B:1010 = A 23 @73 54 @D8
last node (the tail) the reference is a
special value called NULL (usually B:1011 = B
implemented as a non-accessible B:1100 = C 33 NULL
memory position, such as 00.)
B:1101 = D 39 @4C
The figure shows a linked list reference in B:1110 = E
the stack, and its component nodes in FF
B:1111 = F
the heap (arrows are only a visual aid).
Adding elements to linked lists
New elements can be inserted into a linked list by simply:
• Step 0: Creating a new node that contains the new value (the new
object) we want on the list.
• Step 1: Making the new node “point to” a node already in the list.
This will be the new node’s next node in the list.
• Step 2: Changing the reference of the node that was already pointing
to the new node’s next node, so that it now points to the new node.

There are special cases that work slightly differently:


• Appending a new node to the end of the linked list.
• Prepending a new node to the beginning of the list (see the
bottom figure, to the right).
Arrays vs Linked Lists

Array List
Size can
Fixed size
change

One or
more Only linear
dimensions

This is a doubly linked list:


each node “points” to the next node
and also to the previous node.
The Java LinkedList API
Java provides an API in the util library, with classes and
methods to create linked lists.
The library has to be imported in order to use the LinkedList
class.
import java.util.*;
Creating a Linked List in Java
Examples of linked list variable initialisation (i.e. declaration and assignment):
Remember the ()
at the end!
(We are invoking a
LinkedList
constructor method.)

Warning: don’t use double,


int, char or boolean

In Java, a LinkedList can only have objects as its elements. In order to include
primitive type values (int, double, char, …) we need to “wrap” them in an object.
Java provides “wrapper classes” for primitive types. These are what we need for
linked lists.
For instance, if we want a linked list for integer objects, we declare that the
elements in the linked list are going to be members (instances) of the class Integer.
Java Wrapper Classes
Primitive data type Wrapper class
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character

https://www.w3schools.com/java/java_wrapper_classes.asp
Adding items to a linked list

Output
Removing items from a
linked list

Output
Be careful when getting the size!
.size() → for Linked Lists
e.g. int k = zones.size(); // zones is a linked list

.length() → for Strings


e.g. int m = name.length(); // name is a String

.length → for Arrays


e.g. int g = boxes.length; // boxes is an array
There are many methods to manipulate
LinkedList methods in Java Java Linked Lists. Here are a few:
Method Behaviour
int size() Returns the number of elements in the linked list.

void add(E e) Adds element e (an object of type E) at the end of the linked list.
Inserts element e (an object of type E) at the beginning of the linked list. (The node containing the new
void addFirst(E e)
element becomes the new head of the linked list, and it points to (its next node is) the previous head.)
Inserts the specified element, e, at the specified index position in the list. Shifts the element currently at
void add(int index, E e) that position (if any), and any subsequent elements, to the right (i.e., adds one to their “indices”).
Throws IndexOutOfBoundsException if the index is out of range (index < 0 or index > size()).
E removeLast() Removes and returns the last element from the list.
E remove(int index) Removes and returns the element at the specified index position in the list.
Throws IndexOutOfBoundsException if the index is out of range (index < 0 or index >= size()).
Removes the first occurrence of the specified element, e, from this list, if it is present.
boolean remove(E e)
Returns true if the list contained the specified element (false otherwise).
E get(int index) Returns the element at the specified index position. The element is not removed from the list.
Throws IndexOutOfBoundsException if the index is out of range (index < 0 or index >= size()).
E set(int index, E e) Replaces the element at the specified position in the list with the specified element, e.
Throws IndexOutOfBoundsException if the index is out of range (index < 0 or index >= size()).
boolean contains(E e) Returns true if this list contains the specified element.
Returns the index of the first occurrence of the specified element, e, in the list.
int indexOf(E e)
Returns -1 if the list does not contain the element.
void clear() Removes all the elements from this list. The list will be empty after this call returns.
HL-only
content
follows!
Binary search tree traversals
Java
Collections
Framework

You might also like