ma'am audrey's lessons

ITC 120 › Prelim › Arrays

Linear data structures · Lesson 1 of 4

Arrays: the four operations

This lesson teaches:Data structureAlgorithm

Access, traversal, insertion, and deletion, and why some of them cost more than others.

By the end, you can:

  1. describe the four basic operations on an array (access, traversal, insertion, deletion), and write access and traversal in Java;
  2. show which values move when you insert or delete in the middle, and in which order, and write a method that removes a value;
  3. compare arrays and linked lists, and choose one for a task.

You need: the Programming refresher (especially loops and arrays), the Introduction, and scratch paper.

Part 1 · The big idea

Four things we do with data

arr1903142273564

This lesson is about the array, the first linear data structure of the course. Here are both words again:

Array and index

An array is a fixed number of slots, side by side, that all hold the same type of value. Each slot's numbered position is its index, counting from 0.

Linear data structure

A data structure whose items sit one after another, in a line. Each item has one item before it and one after it, except the first and the last. Arrays, linked lists, stacks, and queues are linear.

The array above is named arr. Slot 2 holds 42, so arr[2] is 42. Think of a piso-net shop: a fixed row of numbered units, one user per PC.

A piso-net shop0Ana1Ben2Cris3Dan4EliEach unit has a number: that is the index.One user per unit: one value per slot.The row of units is fixed: the length is fixed.
Unit numbers work like indexes, and each user is like the value in a slot. (Real shops usually number from 1; Java arrays start at 0.)

Every data structure in this course is judged by how well it does these four operations:

OperationWhat it means
AccessGet one value using its index.
TraverseVisit every value, in order.
InsertAdd a new value at a position.
DeleteRemove the value at a position.
Accessget one valueby its indexarr[2]19342756Traversevisit everyvalue, in order19342756index 0, 1, 2, 3, 4Insertadd a valueat a position251020253040→→Deleteremove a valueat a position2010253040←←←
The four operations on one small array.

Where you see them

Different programs lean on different operations:

SituationMostly uses
The registrar's list of 5,000 students in ID order. Pull up one student, or average them all.access and traversal
A sari-sari store's inventory. New stock arrives and old items are dropped all day.insert and delete
An office print queue. Jobs join at the back and leave from the front.insert and delete, at the ends
001 Ana002 Ben003 Cris004 DanRegistrar's student list5,000 students in ID orderaccess + traversalinoutSari-sari store inventorystock comes in, items go outinsert + deletebackfrontOffice print queuejoin at back, leave at frontinsert + delete (ends)
Each situation leans on different operations.

That is why there is no single best structure. The right one depends on what the program does most.

Part 2 · Operation 1

Access: one step, every time

marks140281352493604
int[] marks = {14, 28, 35, 49, 60};
System.out.println(marks[2]);   // 35

Java goes straight to slot 2. It does not look at slots 0 and 1 first. The slots sit side by side in memory, so Java can compute where slot 2 is right away. It takes one step whether the array holds 5 values or 5,000. This is the array's best trick.

Optional: how can Java jump straight to slot 2?

Every spot in the computer's memory has a number, called its address. An array's slots sit side by side, and every slot is the same size (an int takes 4 bytes). So one calculation finds any slot:

address of slot i = start + i × slot size

Here, start is the address where slot 0 begins, i is the index, and slot size is how many bytes one value takes. If marks started at address 1000, slot 2 would start at 1000 + 2 × 4 = 1008. No other slot is looked at. This is also one reason indexes start at 0: slot 0 is zero slots away from the start. (Java hides the real addresses from your program, but the idea is the same.)

index01234marks1428354960address10001004100810121016start + 2 × 4 = 1000 + 8 = 1008Each int takes 4 bytes, so addresses go up by 4.
One calculation finds slot 2. No other slot is checked.

Watch the last index

marks140281352493604✗5?

Indexes start at 0, so the last index is length - 1. For marks (length 5), the last index is 4. There is no slot 5, so marks[5] stops the program with an ArrayIndexOutOfBoundsException. An exception is an error Java reports while the program is running; if nothing handles it, the program stops (see the Programming refresher). This is why loops use i < marks.length, not i <= marks.length.

Part 3 · Operation 2

Traversal: visit every value

Traversal

Visiting every item in a data structure once, in order, to do something with it: print it, add it up, or compare it. In an array, a traversal goes from index 0 to the last index, one slot at a time.

12345visitmarks780851912743884i = 0 → 1 → 2 → 3 → 4Then i = 5 is not < 5 (the length), so the loop stops.
A traversal of marks: five slots, five visits, then the loop stops.

A loop does the visiting. Start at 0, keep going while i is less than the length, and add 1 each round:

for (int i = 0; i < marks.length; i++) {
  System.out.println(marks[i]);
}

You already know this loop. Traversal is just its name in DSA. One pass through the array can answer a question, like "what is the highest score?"

 1int[] marks = {78, 85, 91, 74, 88};
 2int highest = marks[0];
 3for (int i = 1; i < marks.length; i++) {
 4  if (marks[i] > highest) {
 5    highest = marks[i];
 6  }
 7}
 8System.out.println(highest);   // 91

highest starts with a real score, marks[0] (78), so the loop can begin at index 1. Here is the trace table:

imarks[i]marks[i] > highest?highest after
before the loop: highest = marks[0]78
18585 > 78: yes85
29191 > 85: yes91
37474 > 91: no91
48888 > 91: no91

Output: 91.

Why not start highest at 0?

It works for quiz scores, but not always. If every value were negative, like temperatures in a freezer, the answer would wrongly be 0. Starting with marks[0] always uses a real value.

Freezer temperatures (°C)temps-50-21-82highest = 0No temperature is > 0,so it never changes.0 ✗not in the list!highest = temps[0]Starts at -5. Then -2 > -5,so highest becomes -2.-2 ✓
With all-negative values, starting at 0 gives a wrong answer.

Counting with a condition

Add a counter and an if, and the same loop can count. This one counts the passing scores (75 and up):

int[] scores = {88, 72, 95, 64};
int passed = 0;                              // counter starts at 0
for (int i = 0; i < scores.length; i++) {    // visit each score
  if (scores[i] >= 75) {                     // passing?
    passed++;                                // one more pass
  }
}
System.out.println("Passed: " + passed);     // Passed: 2

The counter changes only when the condition is true: for 88 and 95. So the output is Passed: 2.

Try it: predict the output

int[] stock = {12, 0, 7, 3, 9};
int low = 0;
for (int i = 0; i < stock.length; i++) {
  if (stock[i] < 5) {
    System.out.println("Restock item " + i);
    low++;
  }
}
System.out.println("Items to restock: " + low);

Write exactly what this prints. Careful: what does it print, i or stock[i]?

Show the answer
Restock item 1
Restock item 3
Items to restock: 2

Only 0 (at index 1) and 3 (at index 3) are less than 5. The loop prints the index i, not the stock value.

Part 4 · Operations 3 and 4

Insert and delete: shifting

An array's slots sit side by side, and its length is fixed when it is created. So to insert or delete in the middle, other values have to move.

Shifting

Moving a group of values one slot over, all in the same direction: to the right to open a gap, or to the left to close one.

To know where the values end, programs keep two numbers:

NameMeaning
capacity (arr.length)How many slots the array has. It never changes.
sizeHow many slots hold real values right now. We keep it in our own variable.

Insert: later values move right

To insert 25 at index 2 of 10, 20, 30, 40:

  1. Move 40 from slot 3 to slot 4.
  2. Move 30 from slot 2 to slot 3.
  3. Put 25 into slot 2. Size goes from 4 to 5.

Here is the same insert in Java. Step through it line by line:

Walkthrough: insert 25 at index 2

Use Next to follow the loop, or tap a line to jump to it.

01234567size = 0

arr.length = 8

Java makes an array with 8 slots. Its length (capacity) is fixed: it will always be 8.

Step 1 of 10
 1int[] arr = new int[8];      // capacity 8, fixed 2int size = 4;                // 10, 20, 30, 40 are stored 3// insert value v at index k 4for (int i = size; i > k; i--) { 5  arr[i] = arr[i - 1];       // move one slot right 6} 7arr[k] = v; 8size++;

Start from the end

If we moved 30 first, it would land on top of 40, and 40 would be lost. Moving from the end means each value moves into a slot that is already free. That is why the loop counts down: i--.

Wrong: moving 30 firstStart110203040After move 121020303040 was covered up!After move 2, then 25102025303040 is lost. Fix: start from the end (move 40 first).
The mistake: moving 30 first covers 40 before it can move.

Check for room first

Insert needs one free slot. If size == arr.length, every slot is in use, and the loop would write to arr[size], a slot that does not exist: an ArrayIndexOutOfBoundsException. So check first:

if (size == arr.length) {
  System.out.println("The array is full.");
} else {
  // shift, then arr[k] = v; and size++;
}

A Java array cannot grow. To fit more values, a program makes a new, bigger array and copies the values over. (Java's ArrayList does this for you.)

Delete: later values move left

To delete index 1 of 10, 20, 25, 30, 40:

  1. Copy 25 into slot 1, on top of the 20.
  2. Copy 30 into slot 2, then 40 into slot 3.
  3. Size drops from 5 to 4. Slot 4 still holds an old copy of 40, but we stop counting it.

Here is the delete in Java, with the same array:

Walkthrough: delete index 1

Use Next to follow the loop, or tap a line to jump to it.

100201252303404567size = 5

k = 1size = 5

We delete the value at index k = 1: the 20. Every value after it must move one slot left to close the gap.

Step 1 of 9
 1// delete the value at index k 2for (int i = k; i < size - 1; i++) { 3  arr[i] = arr[i + 1];       // move one slot left 4} 5size--;

This time the loop counts up, starting at the gap. Each value moves into the slot that was just copied from.

Array lab

Tap an operation to watch it step by step (Next step). Change the index or value to try other numbers. Each step also shows the line of Java that does it.

Tap an operation above.

being used now moved new value not counted (beyond size)

Try: insert 25 at index 2, then delete index 1. Then insert at index 0 and count the moves.

Part 5 · Why this matters

Access stays cheap. Shifting does not.

Count the work. Inserting at the front means every value moves one slot:

Access arr[3]: one jump10203040500 values? Still one jump.Insert at the front: all move1234102030404 values: 4 moves. 500 values: 500 moves.
Access is one jump at any size. Inserting at the front moves every value.

Here are the counts:

TaskWork
Access any index1 step, no matter the size
Insert at the front of an array holding 4 values4 moves
Insert at the front of an array holding 500 values500 moves
Do that 1,000 timesat least 500 × 1,000 = half a million moves (more, since the array keeps growing)

So the question is not "is the array good?" It is "good for which operation?" Users never complain about 500 moves. They complain that the app froze.

A first look ahead: linked lists

A linked list stores values in nodes: small boxes that each hold one value and an arrow to the next node. You will learn it next. To insert B2 between B and C, it changes two arrows. A, B, and C never move.

A→B→B2→C→null

Here is the same operation in both structures:

TaskArrayLinked list
Get the value at index 500one stepstart at the first node and follow 500 links
Insert, once you are at the spotshift every later valuechange two links
Delete, once you are at the spotshift every later valuechange one link (in the node before it)
Memory per itemjust the valuethe value plus a link
Sizefixed when createdgrows as you add

Remember

The linked list only wins once you have already found the spot. Getting there still takes walking.

Part 6 · Your turn

Practice

Quick check (on paper)

  1. Given marks = {64, 90, 77, 81, 59}, what is marks[4]? What happens with marks[5]?
  2. Insert 15 at index 1 of [5, 10, 20, 25, _]. Which values move, and in what order?
  3. Delete index 0 of [8, 16, 24, 32, _]. Which values move, and in what order?
  4. Which of these would a linked list make easier, and why?
Show the answers
  1. 59. Count from 0: 64, 90, 77, 81, 59. The last index is length − 1 = 4, so marks[5] stops the program with an ArrayIndexOutOfBoundsException.
  2. 25 moves to index 4 first, then 20 to index 3, then 10 to index 2 (3 moves). Then 15 goes into index 1: [5, 15, 10, 20, 25].
  3. 16 moves to index 0 first, then 24 to index 1, then 32 to index 2 (3 moves: deleting at the front moves every later value). Size drops to 3: [16, 24, 32]. (Slot 3 still holds an old 32, but it is not counted.)
  4. Insertion and deletion (questions 2 and 3). A linked list changes one or two links instead of shifting values, once it is at the spot. Access (question 1) is easier in an array.

Coding practice

A canteen freezer should stay at −10 °C or colder. Its thermometer saved five readings: int[] temps = {-12, -5, -18, -3, -9};. Write a program that:

  1. prints all five readings using a loop;
  2. finds and prints the warmest (highest) reading;
  3. prints only the readings warmer than −10 (too warm for the freezer);
  4. counts and prints how many readings were too warm.

Checklist: Did you use a loop? Did warmest start with temps[0]? (Starting at 0 would print 0, a reading that never happened: the trap from Part 3.) Did you use > -10, so that exactly −10 counts as cold enough? You can run it in the Programiz online compiler.

Show one possible answer
public class Main {
  public static void main(String[] args) {
    int[] temps = {-12, -5, -18, -3, -9};

    // 1. print all five readings
    for (int i = 0; i < temps.length; i++) {
      System.out.println(temps[i]);
    }

    // 2. find the warmest (highest) reading
    int warmest = temps[0];
    for (int i = 1; i < temps.length; i++) {
      if (temps[i] > warmest) {
        warmest = temps[i];
      }
    }
    System.out.println("Warmest: " + warmest);

    // 3 and 4. print the readings warmer than -10, and count them
    int tooWarm = 0;
    for (int i = 0; i < temps.length; i++) {
      if (temps[i] > -10) {
        System.out.println(temps[i]);
        tooWarm++;
      }
    }
    System.out.println("Too warm: " + tooWarm);
  }
}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

Output: −12, −5, −18, −3, −9 (one per line), then Warmest: -3, then −5, −3, −9, then Too warm: 3.

Your coding task: remove a value

This task joins Part 3 and Part 4: find a value, then delete it, like crossing a sold-out item off a canteen list. Finish removeValue so it removes the first copy of target and returns the new size. indexOf is finished for you and finds the index. Write about 5 lines where it says YOUR CODE, then run it: the four printed lines must match the comments.

 1public class Main {
 2  // Removes the first copy of target. Returns the new size.
 3  static int removeValue(int[] arr, int size, int target) {
 4    int k = indexOf(arr, size, target);
 5    // YOUR CODE:
 6    // 1. If target is not there (k is -1), return size unchanged.
 7    // 2. Shift every value after index k one slot left.
 8    // 3. Return the new size.
 9
10    return size;
11  }
12
13  // Finished for you: the index of target, or -1 if it is not there.
14  static int indexOf(int[] arr, int size, int target) {
15    for (int i = 0; i < size; i++) {
16      if (arr[i] == target) {
17        return i;
18      }
19    }
20    return -1;
21  }
22
23  // Finished for you: prints only the counted values.
24  static void show(int[] arr, int size) {
25    for (int i = 0; i < size; i++) {
26      System.out.print(arr[i] + " ");
27    }
28    System.out.println();
29  }
30
31  public static void main(String[] args) {
32    int[] arr = {10, 25, 30, 40, 0};   // capacity 5
33    int size = 4;                      // 4 values are counted
34
35    size = removeValue(arr, size, 25);
36    show(arr, size);                   // expected: 10 30 40
37    size = removeValue(arr, size, 99);
38    show(arr, size);                   // expected: 10 30 40
39    size = removeValue(arr, size, 40);
40    show(arr, size);                   // expected: 10 30
41    size = removeValue(arr, size, 10);
42    show(arr, size);                   // expected: 30
43  }
44}

▶ This program runs as is. Try it in the Programiz online compiler: tap Copy, paste it there, and press Run.

Show one possible answer
 1static int removeValue(int[] arr, int size, int target) {
 2  int k = indexOf(arr, size, target);
 3  if (k == -1) {
 4    return size;
 5  }
 6  for (int i = k; i < size - 1; i++) {
 7    arr[i] = arr[i + 1];
 8  }
 9  return size - 1;
10}

Output: 10 30 40, 10 30 40, 10 30, 30. The loop stops before size - 1 because each step reads the next slot, arr[i + 1], the same as the deletion code in Part 4. Removing 99 changes nothing, since it is not there. Removing the last value (40) shifts nothing: only the size drops. You will write a method like indexOf yourself in the Searching lesson (linear search).

Part 7 · Check yourself

Self-check

Not graded. Tap an answer to see if you got it, and read why.

  1. Given int[] marks = {75, 80, 93, 68, 88};, what is marks[3]?

  2. An array has length 5. What happens with arr[5]?

  3. Insert 27 at index 2 of [11, 22, 33, 44, _]. Which values move?

  4. When inserting, why do we shift starting from the end?

  5. Delete index 1 of [10, 25, 30, 40]. What is the array afterward (only the counted values)?

  6. Which operation is the array's best trick?

Score: 0 / 6

Key takeaways

  1. Four operations: access, traversal, insertion, deletion.
  2. Arrays give direct access when you know the index: one step.
  3. Inserting in the middle shifts later values right (start from the end). Deleting shifts them left.
  4. As data grows, repeated shifting means more work for the program.
  5. Arrays and linked lists have different trade-offs. The better choice depends on the operation.

Next lesson: Linked lists.

References

  1. A. Bhargava, Grokking Algorithms. Manning, 2016, Chapter 2.
  2. Oracle, "Arrays," The Java Tutorials. docs.oracle.com
  3. Programiz, "Java Array." programiz.com
  4. N. Dale, D. T. Joyce, and C. Weems, Object-Oriented Data Structures Using Java, 4th ed. Jones & Bartlett, 2018.
  5. ITC 120 Data Structures and Algorithms Syllabus, Faculty of Computing, Engineering, and Technology, Davao Oriental State University.