Starting from linear continuous storage, rethinking data structure

"Data structure" course is equivalent to "data structure and algorithm" most of the time, so we generally say that data structure will involve algorithm< Data structure requires students to complete complex programming according to the data structure theory. To improve the ability of program design, we must learn, observe, draw lessons from and practice.

When reading this article, you should have a certain C/C + + programming foundation, and be able to understand pointers and structs.

1, Overview of data structure

1. The concept of data structure and algorithm

We store complex problems in the computer memory with specific data types (real individuals) and specific storage structures (relationships between real individuals). We call this "specific storage structure" data structure. On the basis of this data structure, the corresponding operation for a certain function (such as search, delete, sort) is called algorithm.

We can simply understand it as: data structure = individual + individual relationship, algorithm = operation of stored data.

2. The standard to measure the algorithm

Through 1, we call the method and step of data processing algorithm. The standard of algorithm includes the following aspects

  • Time complexity: the approximate number of times a program will be executed, not the execution time
  • Space complexity: the maximum memory occupied during the execution of the algorithm
  • Degree of difficulty
  • Robustness

The core content of the algorithm is to study the time complexity and space complexity of the algorithm.

3. The position of data structure in program development

Data structure is the core course in software engineering. In the actual program development, we will use a variety of programming languages to carry out the corresponding functional operations on a variety of data, such as storage, query, deletion, or more complex operations. So data structure, to a certain extent, determines an individual's comprehensive ability in program development.

We can understand it as: program = data storage + data operation (algorithm) + language that can be executed by computer.

4. Basic module of data structure

In order to facilitate our future study, this paper lists the basic knowledge modules of data structure as follows

(1) Linear structure (we can call it linear table)

  • Continuous storage
  • Discrete storage [linked list]
  • One of the two common applications of linear structure stack
  • Two common applications of linear structure -- queue

(2) Nonlinear structure

  • tree
  • chart

2, Data structure and basic algorithm of continuous storage

In data structure, the object of our research is data, followed by the method and step of operating data. Today, we start from the continuous storage in linear structure, and re recognize the data structure from the perspective of code.

Continuous storage is actually a continuous storage structure. We can understand that array is the implementation of continuous storage. Next, we define the data structure of continuous storage through the struct keyword of C language, here we call it array, and study its basic algorithm.

Continuous storage structure is easy to realize the operation of element tracing and reading the i-th element in linear table; However, in the implementation of insert and delete operations, a large number of elements need to be moved. Therefore, it is suitable for storing relatively stable linear tables, such as employee salary table and student status table.

1. Define array

First of all, we define a 01-Arr.cpp file. We need to introduce the basic c language header file, as follows

# Include < stdio. H > / / standard io header, including printf function
# Include < malloc. H > / / include malloc function. On mac, change to sys/malloc.h
# Include < stdlib. H > / / include exit function

Next, we define the structure of the array. The data type contains three members, pBase, len and cnt. The code is as follows

struct Arr
{
    int *pBase; // It stores the address of the first element of the array
    int len;    // The maximum number of elements an array can hold
    int cnt;    // Number of valid elements in current array
};

2. Initialize array

Next, we define the function to initialize the array, and dynamically allocate memory according to the length of the array to store the corresponding array elements. The code is as follows

void init_arr(struct Arr *pArr, int length)
{
    // According to the length of the array, the allocated memory is pBase
    pArr->pBase = (int *)malloc(sizeof(int) * length);
    if (NULL == pArr->pBase)
    {
        printf("Dynamic memory allocation failure");
        exit(-1);
    }
    // Memory allocation successful
    pArr->len = length;
    pArr->cnt = 0;
    return;
}

3. Determine whether the array is empty or full

We can determine whether the array is empty or full according to the effective elements and total elements of the current array, and define the following two functions

// Determine whether the array is empty
bool is_empty(struct Arr *pArr)
{
    // The valid number of the array is 0, that is, the array is empty
    if (0 == pArr->cnt)
    {
        return true;
    }
    // Otherwise, the array is not empty
    else
    {
        return false;
    }
}
// Determine whether the array is full
bool is_full(struct Arr *pArr)
{
    // The effective number of an array is the length of the array, that is, the array is full
    if (pArr->cnt == pArr->len)
    {
        return true;
    }
    // Otherwise, the array is not full
    else
    {
        return false;
    }
}

4. Traverse array elements

The purpose of traversing the array is to print every valid array element to the terminal. According to the current valid number of array, traverse and print each element, we define the following code

// Traversing arrays
void traverse_arr(struct Arr *pArr)
{
    for (int i = 0; i < pArr->cnt; i++)
    {
        printf("%d\t", pArr->pBase[i]);
    }
    printf("\n");
}

5. Add array elements

Appending is to add elements at the end of an array that is not full, as shown in the following code

bool append_arr(struct Arr *pArr, int val)
{
    // Returns false if the array is full
    if (is_full(pArr))
    {
        return false;
    }
    // The array is appended when it is not full
    pArr->pBase[pArr->cnt] = val;
    (pArr->cnt)++;
    return true;
}

6. Insert element

In addition to appending an array, there is also an array insert operation. Insert means to add data at a specific location. The code is as follows

bool insert_arr(struct Arr *pArr, int pos, int val)
{
    // Returns false if the array element is full
    if (is_full(pArr))
    {
        return false;
    }
    // If the position to be inserted is not correct, return false
    if (pos < 0 || pos > pArr->cnt)
    {
        return false;
    }
    // From the position of the last element to the position to be inserted, move the array elements back one bit one by one
    for (int i = pArr->cnt - 1; i >= pos; --i)
    {
        pArr->pBase[i + 1] = pArr->pBase[i];
    }
    // Assign the inserted value to the specified position
    pArr->pBase[pos] = val;
    // Mark the fields of the valid elements of the array plus 1
    (pArr->cnt)++;
    return true;
}

7. Delete element

Delete operation is similar to insert operation, the difference is: when inserting data, start from the insert position, move the following data back, and add elements at the insert position; When deleting data, we need to start at the last bit of the deletion position, and all the subsequent data will move forward, and the data at the deletion position will be covered, as shown in the following code

bool delete_arr(struct Arr *pArr, int pos, int *pVal)
{
    // Returns false if the array element is full
    if (is_full(pArr))
    {
        return false;
    }
    // If the position to be inserted is not correct, return false
    if (pos < 0 || pos > pArr->cnt)
    {
        return false;
    }
    // Assign the value of the deleted element to the passed in pointer variable
    *pVal = pArr->pBase[pos];
    // Move the array elements forward one by one from the position to be deleted to the last position
    for (int i = pos; i < pArr->cnt; ++i)
    {
        pArr->pBase[i] = pArr->pBase[i + 1];
    }
    pArr->cnt--;
    return true;
}

8. Array inversion

The operation of array inversion is to replace the first and last element of the array, the second and last element, and so on. Finally complete the inversion, the following code

void inverse_arr(struct Arr *pArr)
{
    int i = 0;
    int j = pArr->cnt - 1;
    int t;
    while (i < j)
    {
        t = pArr->pBase[i];
        pArr->pBase[i] = pArr->pBase[j];
        pArr->pBase[j] = t;
        ++i;
        --j;
    }
    return;
}

9. Array sorting

Next is a simple sorting process, with two loops in the function. In the first layer of loop, select the element at the current position (starting from the position with index 0, that is, before the loop, the current position is the first element). In the second layer of loop, start from the next element of the element at the current position until the last element, compare the size with the element at the current position one by one, and replace the small element to the current position each time.

At the end of the first cycle, the position with index 0 will be the smallest element, at the end of the second cycle, the position with index 1 will be the second smallest element, and so on. Finally, the array elements will be arranged from small to large, as follows

void sort_arr(struct Arr *pArr)
{
    int i, j, t;
    for (i = 0; i < pArr->cnt; i++)
    {
        for (j = i + 1; j < pArr->cnt; j++)
        {
            if (pArr->pBase[i] > pArr->pBase[j])
            {
                t = pArr->pBase[i];
                pArr->pBase[i] = pArr->pBase[j];
                pArr->pBase[j] = t;
            }
        }
    }
}

3, Testing and verification

Finally, all the test codes are as follows

#include <stdio.h>
#include <sys/malloc.h> // Using # include < malloc. H > in windows
#include <stdlib.h>

// Define array structs
struct Arr
{
    int *pBase; // It stores the address of the first element of the array
    int len;    // The maximum number of elements an array can hold
    int cnt;    // Number of valid elements in current array
};

// Initialize array
void init_arr(struct Arr *pArr, int length)
{
    // Assign allocated memory to pBase
    pArr->pBase = (int *)malloc(sizeof(int) * length);
    if (NULL == pArr->pBase)
    {
        printf("Dynamic memory allocation failure");
        exit(-1);
    }
    // Memory allocation successful
    pArr->len = length;
    pArr->cnt = 0;
    return;
}

// Determine whether the array is empty
bool is_empty(struct Arr *pArr)
{
    // The valid number of the array is 0, that is, the array is empty
    if (0 == pArr->cnt)
    {
        return true;
    }
    // Otherwise, the array is not empty
    else
    {
        return false;
    }
}

// Determine whether the array element is full
bool is_full(struct Arr *pArr)
{
    // The effective number of an array is the length of the array, that is, the array is full
    if (pArr->cnt == pArr->len)
    {
        return true;
    }
    // Otherwise, the array is not full
    else
    {
        return false;
    }
}

// Traversing arrays
void traverse_arr(struct Arr *pArr)
{
    for (int i = 0; i < pArr->cnt; i++)
    {
        printf("%d\t", pArr->pBase[i]);
    }
    printf("\n");
}

// Append array (element)
bool append_arr(struct Arr *pArr, int val)
{
    // Array full returns false
    if (is_full(pArr))
    {
        return false;
    }
    // Add when array is not full
    pArr->pBase[pArr->cnt] = val;
    (pArr->cnt)++;
    return true;
}

// Insert array (element)
bool insert_arr(struct Arr *pArr, int pos, int val)
{
    // Returns false if the array element is full
    if (is_full(pArr))
    {
        return false;
    }
    // If the position to be inserted is not correct, return false
    if (pos < 0 || pos > pArr->cnt)
    {
        return false;
    }
    // From the position of the last element to the position to be inserted, move the array elements back one bit one by one
    for (int i = pArr->cnt - 1; i >= pos; --i)
    {
        pArr->pBase[i + 1] = pArr->pBase[i];
    }
    // Assign the inserted value to the specified position
    pArr->pBase[pos] = val;
    // Mark the fields of the valid elements of the array plus 1
    (pArr->cnt)++;
    return true;
}

// Delete array (element)
bool delete_arr(struct Arr *pArr, int pos, int *pVal)
{
    // Returns false if the array element is full
    if (is_full(pArr))
    {
        return false;
    }
    // If the position to be inserted is not correct, return false
    if (pos < 0 || pos > pArr->cnt)
    {
        return false;
    }
    // Assign the value of the deleted element to the passed in pointer variable
    *pVal = pArr->pBase[pos];
    // Move the array elements forward one by one from the position to be deleted to the last position
    for (int i = pos; i < pArr->cnt; ++i)
    {
        pArr->pBase[i] = pArr->pBase[i + 1];
    }
    pArr->cnt--;
    return true;
}

// Inverted array (element)
void inverse_arr(struct Arr *pArr)
{
    int i = 0;
    int j = pArr->cnt - 1;
    int t;
    while (i < j)
    {
        t = pArr->pBase[i];
        pArr->pBase[i] = pArr->pBase[j];
        pArr->pBase[j] = t;
        ++i;
        --j;
    }
    return;
}

// Array sorting
void sort_arr(struct Arr *pArr)
{
    int i, j, t;
    for (i = 0; i < pArr->cnt; i++)
    {
        for (j = i + 1; j < pArr->cnt; j++)
        {
            if (pArr->pBase[i] > pArr->pBase[j])
            {
                t = pArr->pBase[i];
                pArr->pBase[i] = pArr->pBase[j];
                pArr->pBase[j] = t;
            }
        }
    }
}

// Main function test
int main()
{
    struct Arr arr;
    // Initializes an array of length 6
    init_arr(&arr, 6);

    // Additional elements
    append_arr(&arr, 1);
    append_arr(&arr, 2);
    append_arr(&arr, 3);
    append_arr(&arr, 4);

    traverse_arr(&arr); // The output is 1 2 3 4

    // Insert 6 at index 0
    insert_arr(&arr, 0, 5);
    traverse_arr(&arr); // The output is 5 1 2 3 4

    // Delete element at index 0
    int delval; // Used to receive deleted elements
    delete_arr(&arr, 0, &delval);
    traverse_arr(&arr); // The output is 1 2 3 4

    // Array inversion
    inverse_arr(&arr);
    traverse_arr(&arr); // The output is 4 3 2 1

    // Array sorting
    sort_arr(&arr);
    traverse_arr(&arr); // The output is 1 2 3 4

    return 0;
}

This article originally started from wx subscription number: geek development up, prohibit reprint

Tags: Back-end C++ data structure Algorithm array

Posted by tomasd on Sun, 13 Jun 2021 04:05:22 +0930