[Learn Data Structure 01 from Today] Arrays

Posted by jpratt on Fri, 15 Nov 2019 03:43:57 +0100

When interviewing, you often ask the difference between an array and a list of chains. Many people answer, "A list of chains is suitable for insertion and deletion, with a time complexity of O(1); an array is suitable for searching, and a time complexity of O(1)."In fact, this statement is inaccurate.Arrays are suitable for lookup operations, but the time complexity of lookups is not O (1).The time complexity is O(logn) even if you are looking for an ordered array with a dichotomy.Therefore, the correct statement should be that arrays support random access, and random access based on subscripts has an O (1) time complexity.

Arrays are a basic data type in every programming language.However, it is not only a data type in a programming language, but also the most basic data structure.Although arrays may seem basic and simple, I estimate that many people do not understand the essence of this underlying data structure.In most programming languages, arrays start numbering from 0, but have you ever wondered why arrays start numbering from 0, not from 1?Wasn't it more in line with human thinking habits from the beginning?With this problem to learn the next content, learning with problems often works better!!!

What is an array?I guess you already have an answer in your mind.However, I would like to give you a professional explanation.Array is a linear table data structure.It uses a continuous set of memory space to store a set of data of the same type.There are several keywords in this definition, and after understanding these keywords, I think you will have a thorough understanding of the concept of arrays.Here's a click-dial for you from my point of view.

The first is the Linear List.As the name implies, a linear table is a line-like structure for data rows.Data on each linear table has at most two directions, front and back.In fact, in addition to arrays, chained lists, queues, stacks, and so on are also linear table structures.The opposite concepts are non-linear tables, such as binary trees, heaps, graphs, and so on.Nonlinearity is because in a non-linear table, there is not a simple back-and-forth relationship between data.

The second is continuous memory space and the same type of data.Because of these two limitations, it has a killer mace feature: random access.However, there are advantages and disadvantages. These two restrictions also make many operations of arrays very inefficient, such as deleting or inserting a data into an array. To maintain the continuity of memory data, arrays can cause insertion and deletion to be inefficient, whereas array queries can be efficient.

Array java code:

package array;

/**
 * 1) Array insertion, deletion, random access according to subscripts;
 * 2)The data in the array is of type int;
 *
 * Author: Zheng
 * modify: xing, Gsealy
 */
public class Array {
    //Define integer data to save data
    public int data[];
    //Define Array Length
    private int n;
    //Actual Number in Definition
    private int count;

    //Construction method, defining array size
    public Array(int capacity){
        this.data = new int[capacity];
        this.n = capacity;
        this.count=0;//At first none of the numbers were stored, so 0
    }

    //Based on the index, find the elements in the data and return
    public int find(int index){
        if (index<0 || index>=count) return -1;
        return data[index];
    }

    //Insert Element: Head Insert, Tail Insert
    public boolean insert(int index, int value){
        //No elements in array 

        //if (index == count && count == 0) {
        //    data[index] = value;
        //    ++count;
        //    return true;
        //}

        // Array space full
        if (count == n) {
            System.out.println("No place to insert");
            return false;
        }
        // If the count is not full, you can insert the data into the array
        // Illegal location
        if (index < 0||index > count ) {
            System.out.println("Illegal location");
            return false;
        }
        // Legal Location
        for( int i = count; i > index; --i){
            data[i] = data[i - 1];
        }
        data[index] = value;
        ++count;
        return true;
    }
    //Delete elements from the array based on the index
    public boolean delete(int index){
        if (index<0 || index >=count) return false;
        //Move the following element one place forward, starting at the deletion position
        for (int i=index+1; i<count; ++i){
            data[i-1] = data[i];
        }
        //Delete the element at the end of the array This code doesn't need to be or can
        /*int[] arr = new int[count-1];
        for (int i=0; i<count-1;i++){
            arr[i] = data[i];
        }
        this.data = arr;*/

        --count;
        return true;
    }
    public void printAll() {
        for (int i = 0; i < count; ++i) {
            System.out.print(data[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Array array = new Array(5);
        array.printAll();
        array.insert(0, 3);
        array.insert(0, 4);
        array.insert(1, 5);
        array.insert(3, 9);
        array.insert(3, 10);
        //array.insert(3, 11);
        array.printAll();
    }
}

GenericArray Array Code

public class GenericArray<T> {
    private T[] data;
    private int size;

    // Construct Array based on incoming capacity
    public GenericArray(int capacity) {
        data = (T[]) new Object[capacity];
        size = 0;
    }

    // Parameterless construction method, default array capacity is 10
    public GenericArray() {
        this(10);
    }

    // Get Array Capacity
    public int getCapacity() {
        return data.length;
    }

    // Gets the current number of elements
    public int count() {
        return size;
    }

    // Determine if the array is empty
    public boolean isEmpty() {
        return size == 0;
    }

    // Modify elements in index position
    public void set(int index, T e) {
        checkIndex(index);
        data[index] = e;
    }

    // Get the element corresponding to the index position
    public T get(int index) {
        checkIndex(index);
        return data[index];
    }

    // See if the array contains element e
    public boolean contains(T e) {
        for (int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return true;
            }
        }
        return false;
    }

    // Gets the subscript of the corresponding element, not found, returns -1
    public int find(T e) {
        for ( int i = 0; i < size; i++) {
            if (data[i].equals(e)) {
                return i;
            }
        }
        return -1;
    }


    // At index position, insert element e, time complexity O(m+n)
    public void add(int index, T e) {
        checkIndex(index);
        // If the current number of elements equals the array capacity, expand the array to twice its original size
        if (size == data.length) {
            resize(2 * data.length);
        }

        for (int i = size - 1; i >= index; i--) {
            data[i + 1] = data[i];
        }
        data[index] = e;
        size++;
    }

    // Insert element into array header
    public void addFirst(T e) {
        add(0, e);
    }

    // Insert element to end of array
    public void addLast(T e) {
        add(size, e);
    }

    // Delete the element at index position and return
    public T remove(int index) {
        checkIndexForRemove(index);

        T ret = data[index];
        for (int i = index + 1; i < size; i++) {
            data[i - 1] = data[i];
        }
        size --;
        data[size] = null;

        // Compact
        if (size == data.length / 4 && data.length / 2 != 0) {
            resize(data.length / 2);
        }

        return ret;
    }

    // Delete the first element
    public T removeFirst() {
        return remove(0);
    }

    // Delete end element
    public T removeLast() {
        return remove(size - 1);
    }

    // Remove the specified element from the array
    public void removeElement(T e) {
        int index = find(e);
        if (index != -1) {
            remove(index);
        }
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));
        builder.append('[');
        for (int i = 0; i < size; i++) {
            builder.append(data[i]);
            if (i != size - 1) {
                builder.append(", ");
            }
        }
        builder.append(']');
        return builder.toString();
    }


    // Expansion Method, Time Complexity O(n)
    private void resize(int capacity) {
        T[] newData = (T[]) new Object[capacity];

        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }

    private void checkIndex(int index) {
        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Add failed! Require index >=0 and index <= size.");
        }
    }

    private void checkIndexForRemove(int index) {
        if(index < 0 || index >= size) {
            throw new IllegalArgumentException("remove failed! Require index >=0 and index < size.");
        }
    }
}

Here, go back to the original question:

From the memory model of array storage, the most precise definition of "subscript" should be "offset".As mentioned earlier, if a is used to represent the first address of an array, a[0] is the position offset to zero, that is, the first address, and a[k] is the position offset from K type_size s, so this formula is all you need to calculate the memory address of a[k]:

a[k]_address = base_address + k * type_size

However, if the array starts counting from 1, the memory address where we compute the array element a[k] becomes:

a[k]_address = base_address + (k-1)*type_size

Comparing the two formulas, it is easy to find that from the beginning of numbering, there is one more subtraction operation for each random access to array elements, which is one more subtraction instruction for CPU.Then you can think about how the memory addressing formula for two-dimensional arrays is analogous.Interested ones can comment in the comments area oh QAQ

Array is a very basic data structure, and random access to array elements through subscripts is a very basic programming operation, so the optimization of efficiency should be as high as possible.So to reduce one subtraction operation, the array is numbered from 0 instead of from 1.
But I don't think any more explanations above are overwhelming proof that the starting number of an array is not zero.So I think the most important reason may be historical.

With regard to arrays, it can be said to be the most basic and simplest data structure.Arrays use a contiguous block of memory space to store a set of data of the same type. The most important feature is that they support random access, but insert and delete operations become less efficient, with an average time complexity of O(n).In normal business development, we can use container classes provided by programming languages directly, but if it is a particularly low-level development, using arrays directly may be more appropriate.

If this article helps you a little, please give a compliment, thank you~

Finally, if there are any deficiencies or inaccuracies, you are welcome to correct the criticism and appreciate it!If in doubt, please leave a message and reply immediately!

Welcome to pay attention to my public number, discuss technology together, yearn for technology, and pursue technology. Well, you're friends now.

Topics: Java Programming less