Data structure: linear table of linear structure

Keywords: Java C

Even if there is no talent, as long as you are willing to spend a little time every day, do the same thing, unconsciously, you will go far.

What is a linear table?

A linear table is a finite sequence of n (n > = 0) elements. In the table, there is a linear logical relationship between elements:
(1) There is only one start node in the table;
(2) There is only one terminal node;
(3) Except for the start node, each node in the table has only one predecessor node;
(4) Except terminal nodes, each node in the table has only one successor node;
According to their relationship, they can be arranged into an existing linear sequence, which is recorded as: (a1, a2,..., an)
For example, 26 English alphabets (A,B,C,...,X,Y,Z) are a linear table
 ai (1 < = I < = n) here belongs to the same data object and has the same data type. Data elements in linear tables
 The number n is the length of the linear table, which is called table length. When n=0, it is an empty table. i is the bit order of data element ai.

How to store linear tables

Linear tables can be stored in two ways: sequential storage and chained storage

(1) Sequence table

Sequential storage is to store the data elements of linear table in sequence with a piece of memory with continuous address.
The sex table with sequential storage structure is called sequential table, and the logically adjacent data elements in the sequential table are also adjacent in the physical storage location.
As long as the starting position of the linear table is determined, any data in the linear table can be accessed randomly:
The address of the ith element is: Loc(ai) = Loc(a1) + size * (i - 1) where size is the space occupied by each element.
Implementation of C language version
#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define NOTFOUND -1
#define MAXSIZE 100
#define seqNodeDataType int
//Definition of structure
typedef struct seqNode{

    seqNodeDataType data[MAXSIZE];
    int length;

}SeqNode;
//Initialization
void Init_SeqList(SeqNode * L){
    L->length = 0;
}
//Sentence blank
int IsEmpty_SeqList(SeqNode L){

    if (L.length == 0) {
        return TRUE;
    } else {
        return FALSE;
    }
}
//Sentence full
int IsFull_SeqList(SeqNode L){

    if (L.length == MAXSIZE - 1) {
        return TRUE;
    } else {
        return FALSE;
    }
}
//Get real length
int GetListLength_SeqList(SeqNode L){
    return L.length;
}
//Get the element at index
seqNodeDataType GetElem_SeqList(SeqNode L, int index){

    if (index < 0 || index >= L.length) {
        return ERROR;
    }

    return L.data[index];
}
//Search by value
int IndexOf_SeqList(SeqNode L, seqNodeDataType elem){

    for (int i = 0; i < L.length; ++i) {

        if (L.data[i] == elem) {
            return i;
        }
    }

    return NOTFOUND;
}
//Printout
void Print_SeqList(SeqNode L){

    printf("[");
    for (int i = 0; i < L.length; ++i) {

        if (i == L.length - 1) {
            printf("%d", L.data[i]);
        } else {
            printf("%d,", L.data[i]);
        }
    }
    printf("]\n");
}
//Insert element at index
int InsertOfIndex_SeqList(SeqNode *L, int index, seqNodeDataType elem){

    if (index < 0 || index > L->length) {
        return ERROR;
    }
    
    if (IsFull_SeqList(*L)) {
        return ERROR;
    }
    for (int i = L->length; i > index; --i) {

        L->data[i] = L->data[i - 1];

    }

    L->data[index] = elem;
    L->length++;

    return OK;
}
//Add element at the beginning
int InsertFirst_SeqList(SeqNode *L, seqNodeDataType elem){
    InsertOfIndex_SeqList(L, 0, elem);
}
//Tail add element
int InsertLast_SeqList(SeqNode *L, seqNodeDataType elem){
    InsertOfIndex_SeqList(L, L->length, elem);
}
//Delete elements
int DeleteOfIndex_SeqList(SeqNode *L, int index, seqNodeDataType *result){

    if (index < 0 || index > L->length) {
        return ERROR;
    }

    if (IsEmpty_SeqList(*L)) {
        return ERROR;
    }

    for (int i = index; i < L->length - 1; ++i) {
        L->data[i] = L->data[i + 1];
    }

    L->length--;

    return OK;
}
//wipe data
int Clear_SeqList(SeqNode *L){
    L->length = 0;
    return OK;
}
What are the disadvantages
Because the underlying implementation of the sequence table is an array, and the capacity of the array cannot be changed, the biggest problem is how much space allocation is appropriate?
Too small data can not continue to store, and too large space waste. High level language can be used to optimize the sequence table and realize dynamic array expansion.
Java implementation
package cn.boom.list;

public class SeqList<T> {

    private T[] data;
    private int size;

    //Non parametric structure
    public SeqList(){
        data = (T[]) new Object[10];
        size = 0;
    }

    //Structures with parameters: parameter capacity
    public SeqList(int capacity) {
        data = (T[]) new Object[capacity];
        size = 0;
    }

    /**
     * Get the real length (number of data)
     * @return size
     */
    public int getSize(){
        return this.size;
    }

    /**
     * Get elements of index location
     * @param index
     * @return data[index]
     * @throws IllegalArgumentException Illegal parameter exception
     */
    public T getIndexOf(int index) throws IllegalArgumentException{
        //Parameter validity verification
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Illegal Index !");
        }
        return this.data[index];
    }

    //Modified value
    public void set(int index, T elem) {
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Illegal Index !");
        }
        data[index] = elem;
    }

    /**
     * Search by value return elem first occurrence subscript not found return - 1
     * @param elem
     * @return index
     */
    public int locationElem(T elem){

        for (int i = 0; i < this.size; i++) {

            if (elem.equals(this.data[i])) {
                return i;
            }
        }
        return -1;
    }

    //Element present or not
    public boolean contains(T elem){
        return locationElem(elem) != -1;
    }

    //Whether the table is empty
    public boolean isEmpty(){
        return (size == 0);
    }

    //Whether the table is empty
    public boolean isFull(){
        return (size == data.length);
    }

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

    //Insert an element at index
    public void add(int index, T elem) {

        //Parameter validity verification

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Illegal Index ! index is " + index);
        }

        if (isFull()) {
            updateCapacity(data.length * 2);
        }

        //Data move backward after index
        for (int i = size; i > index; i--) {
            this.data[i] = this.data[i - 1];
        }

        this.data[index] = elem;

        size++;
    }

    //Add element at the beginning of array
    public void addFirst(T elem) {
        add(0, elem);
    }

    //Add elements at the end of the array
    public void addLast( T elem){
        add(this.size,elem);
    }


    //Update array capacity
    public void updateCapacity(int newCapacity) {

        T[] newArray = (T[]) new Object[newCapacity];

        for (int i = 0; i < size; i++) { // copy the data in the original array
            newArray[i] = data[i];
        }

        this.data = newArray;

    }

    //Delete the element with index as its subscript and return
    public T remove(int index){

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Illegal Index ! index is " + index);
        }

        T elem = data[index];

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

        size--;

        if (size < data.length / 2) { //Shrinkage capacity
            updateCapacity(data.length / 2);
        }

        return elem;
    }

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

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

    @Override
    public String toString() {

        StringBuilder res = new StringBuilder();

        res.append("SeqList{");

        res.append(" data=[");

        for (int i = 0; i < this.size; i++) {

            res.append(this.data[i].toString());

            if (i != size - 1) {
                res.append(',');
            }
        }
        res.append("], size=" + size +  ", capacity=" + getCapacity() + " }");

        return res.toString();
    }
}

Although the above code realizes the dynamic expansion and reduction of array space, the sequence table is still a non dynamic storage structure.
The following describes the list of dynamic storage structures.
(2) Single chain table
Linked list is a set of arbitrary storage units to store data elements in a linear table. This set of storage units can be continuous or discontinuous.
In order to establish a linear relationship between data elements, for each data element an, in addition to storing its own information, it must also contain information indicating the storage location of the direct successor elements of the element,
These two parts of information form a "node", that is, each node includes at least two domains, one domain stores data element information, which is called data domain; the other domain stores the address of the direct successor element, which is called pointer domain.


Sometimes for the convenience of operation, a node is added before the first node of a single chain table, which is called the head node. The data field of the head node can store information such as title, table length, etc., or it can not store any information. Its pointer field stores the first address of the first node, and the head node points from the head pointer.

Single chain table C
#include <stdio.h>
#include <stdlib.h>
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define NOTFOUND -1
#define linkedListDataType int

typedef struct linkedNode{

    linkedListDataType data;
    struct linkedNode* next;

}LNode;

//Establishing single chain table by head insertion
int CreateHead_LinkedList(LNode ** H){

    (*H)->next = NULL;

    int elem;

    scanf("%d",&elem);

    while (elem != -1) {

        LNode* s = (LNode *) malloc(sizeof(LNode));
        s->data = elem;

        s->next = (*H)->next;
        (*H)->next = s;

        scanf("%d", &elem);

    }

    return OK;
}
//Initialize linked list
LNode *Init_LinkedList() {

    LNode *H = (LNode *) malloc(sizeof(LNode));

    if (H == NULL) {
        return ERROR;
    }

    H->next = NULL;
    return H;
}

//Establishing single chain table by tail insertion
int CreateTail_LinkedList(LNode ** H){

    (*H)->next = NULL;

    LNode *p = *H;
    int elem;

    scanf("%d",&elem);

    while (elem != -1) {

        LNode* s = (LNode *) malloc(sizeof(LNode));
        s->data = elem;
        s->next = NULL;
        p->next = s;
        p = s;

        scanf("%d", &elem);

    }

}
//Get link length
int GetSize_LinkedList(LNode *H){

    LNode *p = H;
    int size = 0;

    while (p->next != NULL) {
        size++;
        p = p->next;
    }

    return size;

}
//Judge whether the list is empty
int IsEmpty(LNode *H){
    if ( H == NULL || GetSize_LinkedList(H) == 0) {
        return 1;
    }
    return 0;
}

//Output print list
void Print_LinkedList(LNode *H){

    LNode *p = H;
    printf("head -> ");

    while (p->next != NULL) {

        printf("%d -> ", p->next->data);

        p = p->next;
    }

    printf("NULL\n");

}
//Get index node
LNode* GetNode_LinkedList(LNode *H, int index) {

    if (index == -1) {
        return H;
    }

    LNode *p = H;
    int count = 0;

    while (p->next != NULL) {

        p = p->next;

        if (index == count) {
            return p;
        }
        count++;
    }
    return NULL;

}

//Delete nodes by index
int DeleteNodeByIndex_LinkedList(LNode *H, int index) {

    LNode *p = GetNode_LinkedList(H, index - 1);
    LNode *q = p->next;
    p->next = p->next->next;
    free(q);
    return OK;
}
//Insert a node at the index
int InsertNodeIndexOf_LinkedList(LNode *H, int index, linkedListDataType elem) {

    if (index > GetSize_LinkedList(H)) {
        return ERROR;
    }

    LNode *p = GetNode_LinkedList(H, index - 1);

    LNode* s = (LNode *) malloc(sizeof(LNode));

    if (s == NULL) {
        return ERROR;
    }

    s->data = elem;

    s->next = p->next;
    p->next = s;

    return OK;
}
//Insert an element at the end of the list
int InsertNodeTail_LinkedList(LNode *H, linkedListDataType elem) {

    InsertNodeIndexOf_LinkedList(H,GetSize_LinkedList(H),elem);
    return OK;
}

//Modify the value of the node at the index
int UpdateNodeByIndex_LinkedList(LNode *H, int index, linkedListDataType elem){

    LNode *p = GetNode_LinkedList(H, index);
    p->data = elem;
    return OK;

}
//Delete duplicate element node
void DeleteRepeatElem(LNode *H){

    if (H == NULL) {
        return;
    }

    LNode *p = H->next;

    if (p == NULL) {
        return;
    }

    while (p->next != NULL) {

        LNode *q = p->next;

        while (q != NULL) {

            if (p->data == q->data) {
                //Delete q node
                LNode *t = q;
                q = q->next;
                free(t);
                p->next = q;

            } else {
                q = q->next;
            }

        }
        p = p->next;
    }

}
Java implementation of single chain table
package cn.boom.list;

public class LinkedList<T> {

    private Node head;//Virtual head node
    private int size;//Table length

    private class Node {

        private T data;
        private Node next;

        public Node() {
            this.data = null;
            this.next = null;
        }

        public Node(T data) {
            this.data = data;
            this.next = null;
        }

        public Node(T data, Node node) {
            this.data = data;
            this.next = node;
        }

    }

    public LinkedList() {
        this.head = new Node();
        this.size = 0;
    }

    /**
     * Get link length
     * @return
     */
    public int getSize() {
        return this.size;
    }

    /**
     * Judge whether the list is empty
     * @return
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Add a new element in the index(0-size) position of the linked list
     * @param index
     * @param elem
     */
    public void add(int index, T elem) {

        if (index < 0 || index > size) {
            throw new IllegalArgumentException("Index Is Illegal Argument ! index = " + index);
        }

        Node node = this.head;

        for (int i = 0; i < index ; i++) { //Find the previous node to insert the subscript
            node = node.next;
        }

        Node e = new Node(elem);
        //Insert Knot
        e.next = node.next;
        node.next = e;

        this.size++;
    }

    /**
     * Add new elements at the head of the list
     * @param elem
     */
    public void addFirst(T elem) {
        add(0,elem);
    }

    /**
     * Add new elements at the end of the list
     * @param elem
     */
    public void addLast(T elem) {
        add(size,elem);
    }

    /**
     * Get the element at the index(0-size) position of the linked list
     * @param index
     * @return
     */
    public T get(int index) {
    
        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Index Is Illegal Argument ! index = " + index);
        }

        Node node = this.head.next;

        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        return node.data;
    }

    /**
     * Modify the element at the index(0-size) position of the linked list
     * @param index
     * @param elem
     */
    public void set(int index, T elem) {

        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Index Is Illegal Argument ! index = " + index);
        }

        Node node = this.head.next;

        for (int i = 0; i < index; i++) {
            node = node.next;
        }
        node.data = elem;
    }

    /**
     * Query whether the element is included in the table
     * @param elem
     * @return
     */
    public boolean contains(T elem) {

        Node node = this.head.next;

        while (node != null) {

            if (node.data.equals(elem)) {
                return true;
            }
            node = node.next;
        }
        return false;
    }

    /**
     * Delete the node at index(0-size) and return data
     * @param index
     * @return
     */
    public T remove(int index) {

        if (index < 0 || index >= size) {
            throw new IllegalArgumentException("Index Is Illegal Argument ! index = " + index);
        }

        Node node = this.head.next;

        for (int i = 0; i < index - 1; i++) { //Find the previous node to delete
            node = node.next;
        }
        Node s = node.next;
        node.next = s.next;
        s.next = null;
        this.size--;

        return s.data;
    }

    /**
     * Remove element e from table
     * @param elem
     */
    public void removeElement(T elem) {

        Node preNode = this.head;
        Node node = preNode.next;

        while (node != null) {

            if (node.data.equals(elem)) {
                preNode.next = node.next;
                node.next = null;
                node = preNode.next;
                this.size--;
                continue;
            }

            preNode = node;
            node = node.next;
        }
    }

    @Override
    public String toString() {

        Node node = this.head.next;
        StringBuilder res = new StringBuilder();
        res.append("head -> ");
        for (int i = 0; i < this.size; i++) {
            res.append(node.data.toString() + " -> ");
            node = node.next;
        }
        res.append("NULL");
        return res.toString();
    }
}

Advantages and disadvantages of sequence list and chain list

Advantages of sequence table:
(1) Using array to store data elements is simple and easy to implement.
(2) No additional storage overhead is needed to represent the logical relationship between nodes.
(3) High storage density.
(4) Sequence table can access nodes randomly according to element bit order.
Disadvantages:
(1) When doing insert and delete operations, a large number of data elements must be moved, which is inefficient.
(2) To occupy continuous storage space, storage allocation can only be done in advance. If the estimation is too large, it may lead to a large number of empty rear; if the pre allocation is too small, it will cause data overflow.
The advantages and disadvantages of linked list are just opposite to the sequence list.

Reference

[1] Wang Shuyan. Data structure and algorithm: People's post and Telecommunications Press
Published 9 original articles, won praise 10, visited 4477
Private letter follow

Posted by kyoru on Wed, 15 Jan 2020 00:27:56 -0800