Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Principles and C Language Implementation of Sequential Linear Lists

Tech 2

Sequential Storage Concept of Linear Lists

A linear list is a finite sequence of data elements, denoted as $L=(a_0, a_1, \dots, a_{n-1})$, where $L$ is the list name, $a_i$ is the data element, and $n$ is the length of the list. When the elements of linear list $L$ are stored consecutively in computer memory, this is called sequential storage of the linear list.

Characteristics of Linear Lists

  • For a non-empty list, $a_0$ is the head element with no predecessor, and $a_{n-1}$ is the tail element with no successor
  • Each middle element $a_i$ has exactly one direct predecessor $a_{i-1}$ and one direct successor $a_{i+1}$

Features of Sequential Storage Structure

  • Elements that are logically adjacent ($a_i, a_{i+1}$) also have adjacent storage locations
  • Supports random access by memory address
  • High storage density, defined as $\text{Storage Density} = \frac{\text{Storage space occupied by data elements}}{\text{Total storage space occupied by the data structure}}$

Sequential Storage Representation in C

We can use a struct combined with a one-dimensional array to describe the sequential storage structure of a linear list:

#define MAX_CAPACITY 100
typedef int elem_type;

typedef struct {
    elem_type data[MAX_CAPACITY];  // Storage space for the list
    int last_idx;                  // Index of the last element in the linear list
} SeqList;

Note: last_idx stores the index of the final element in the list, so the actual length of the list is last_idx + 1.

Basic Operations of Sequential Lists

1. Create Empty List

Creates and initializes an empty linear list, including memory allocation and member variable initialization.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

SeqList* seq_list_create(void) {
    SeqList* new_list = (SeqList*)malloc(sizeof(SeqList));
    if (new_list == NULL) {
        printf("seq_list_create: Memory allocation failed\n");
        return NULL;
    }
    new_list->last_idx = -1;
    return new_list;
}

2. Clear List

Resets the list to an empty state by resetting the last element index and clearing stored data.

int seq_list_clear(SeqList* list) {
    if (list == NULL) {
        printf("seq_list_clear: Invalid null list pointer\n");
        return -1;
    }
    memset(list->data, 0, sizeof(elem_type) * (list->last_idx + 1));
    list->last_idx = -1;
    return 0;
}

3. Check if List is Empty

Determines if the list has no elements by checking if the last element index is -1.

int seq_list_is_empty(const SeqList* list) {
    if (list == NULL) return -1;
    return (list->last_idx == -1) ? 1 : 0;
}

4. Get List Length

Returns the total number of elements in the list.

int seq_list_get_length(const SeqList* list) {
    if (list == NULL) {
        printf("seq_list_get_length: Invalid null list pointer\n");
        return -1;
    }
    return list->last_idx + 1;
}

5. Display List Elements

Prints all elements of the list to standard output.

void seq_list_print(const SeqList* list) {
    if (list == NULL) {
        printf("seq_list_print: Invalid null list pointer\n");
        return;
    }
    if (list->last_idx == -1) {
        printf("Current list is empty\n");
        return;
    }
    for (int i = 0; i <= list->last_idx; i++) {
        printf("%d ", list->data[i]);
    }
    printf("\n");
}

6. Free List Memory

Releases the dynamically allocated memory for the list and nullifies the pointer to avoid dangling references.

int seq_list_free(SeqList* list) {
    if (list == NULL) {
        return -1;
    }
    free(list);
    list = NULL;
    return 0;
}

Core Operations of Sequential Lists

1. Get Element by Index

Retrieves the value of the element at the specified index.

elem_type seq_list_get_elem(const SeqList* list, int index) {
    if (list == NULL) {
        printf("seq_list_get_elem: Invalid null list pointer\n");
        return (elem_type)-1;
    }
    if (index < 0 || index > list->last_idx) {
        printf("seq_list_get_elem: Index out of bounds\n");
        return (elem_type)-1;
    }
    return list->data[index];
}

2. Locate Element by Value

Finds the index of the first occurrence of a specified value in the list, returns -1 if the value is not found.

int seq_list_locate_elem(const SeqList* list, elem_type value) {
    if (list == NULL) {
        return -1;
    }
    for (int i = 0; i <= list->last_idx; i++) {
        if (list->data[i] == value) {
            return i;
        }
    }
    return -1;
}

3. Insert Elements

Front Insert

Inserts an element at the start of the list, requires shifting all existing elements one position to the right.

int seq_list_push_front(SeqList* list, elem_type value) {
    if (list == NULL || list->last_idx >= MAX_CAPACITY - 1) {
        printf("seq_list_push_front: Invalid parameters or list is full\n");
        return -1;
    }
    list->last_idx++;
    for (int i = list->last_idx; i > 0; i--) {
        list->data[i] = list->data[i-1];
    }
    list->data[0] = value;
    return 0;
}

Back Insert

Inserts an element at the end of the list, no element shifting required for high efficiency.

int seq_list_push_back(SeqList* list, elem_type value) {
    if (list == NULL || list->last_idx >= MAX_CAPACITY -1) {
        printf("seq_list_push_back: Invalid parameters or list is full\n");
        return -1;
    }
    list->data[++list->last_idx] = value;
    return 0;
}

Arbitrary Position Insert

Inserts an element at the specified index, shifts subsequent elements to the right to make space. If the index exceeds the current list langth, inserts at the end.

int seq_list_insert(SeqList* list, int index, elem_type value) {
    if (list == NULL || list->last_idx >= MAX_CAPACITY -1) {
        printf("seq_list_insert: Invalid parameters or list is full\n");
        return -1;
    }
    if (index < 0) {
        printf("seq_list_insert: Index out of bounds\n");
        return -1;
    }
    if (index > list->last_idx) {
        list->data[++list->last_idx] = value;
        return 0;
    }
    list->last_idx++;
    for (int i = list->last_idx; i > index; i--) {
        list->data[i] = list->data[i-1];
    }
    list->data[index] = value;
    return 0;
}

4. Delete Element by Index

Removes the element at the specified index, shifts all subsequent elements one position to the left to fill the gap.

int seq_list_delete(SeqList* list, int index) {
    if (list == NULL || list->last_idx == -1 || index < 0 || index > list->last_idx) {
        printf("seq_list_delete: Invalid parameters or empty list\n");
        return -1;
    }
    for (int i = index; i < list->last_idx; i++) {
        list->data[i] = list->data[i+1];
    }
    list->last_idx--;
    return 0;
}

5. Merge Two Lists

Merges all unique elements from the second list into the first list, skipping dupliacte values.

int seq_list_merge(SeqList* list1, const SeqList* list2) {
    if (list1 == NULL || list2 == NULL) {
        return -1;
    }
    for (int i = 0; i <= list2->last_idx; i++) {
        if (seq_list_locate_elem(list1, list2->data[i]) == -1) {
            seq_list_push_back(list1, list2->data[i]);
        }
    }
    return 0;
}

6. Remove Duplicate Elements

Removes duplicate values from the list, retaining only the first occurrence of each element.

int seq_list_remove_duplicates(SeqList* list) {
    if (list == NULL) {
        printf("seq_list_remove_duplicates: Invalid null list pointer\n");
        return -1;
    }
    if (list->last_idx <= 0) {
        return 0;
    }
    int i = 1;
    while (i <= list->last_idx) {
        int j = i -1;
        int duplicate_found = 0;
        while (j >= 0) {
            if (list->data[i] == list->data[j]) {
                seq_list_delete(list, i);
                duplicate_found = 1;
                break;
            }
            j--;
        }
        if (!duplicate_found) {
            i++;
        }
    }
    return 0;
}

Test Cases

Insert and Delete Test

void test_insert_delete(void) {
    SeqList* my_list = seq_list_create();
    if (my_list == NULL) {
        printf("Failed to create list\n");
        return;
    }
    seq_list_push_back(my_list, 66);
    seq_list_push_back(my_list, 100);
    seq_list_push_back(my_list, 22);
    seq_list_push_front(my_list, 12);
    seq_list_insert(my_list, 3, 76);
    seq_list_print(my_list);

    seq_list_delete(my_list, 2);
    seq_list_print(my_list);

    seq_list_free(my_list);
}

List Merge Test

void test_merge(void) {
    SeqList* list_a = seq_list_create();
    seq_list_push_back(list_a, 10);
    seq_list_push_back(list_a, 20);
    seq_list_push_back(list_a, 30);

    SeqList* list_b = seq_list_create();
    seq_list_push_back(list_b, 30);
    seq_list_push_back(list_b, 50);

    seq_list_merge(list_a, list_b);
    seq_list_print(list_a);

    seq_list_free(list_a);
    seq_list_free(list_b);
}

Duplicate Removal Test

void test_remove_duplicates(void) {
    SeqList* my_list = seq_list_create();
    seq_list_push_back(my_list, 10);
    seq_list_push_back(my_list, 10);
    seq_list_push_back(my_list, 10);
    seq_list_push_back(my_list, 10);
    seq_list_push_back(my_list, 10);

    seq_list_print(my_list);
    seq_list_remove_duplicates(my_list);
    seq_list_print(my_list);

    seq_list_free(my_list);
}

Header File Definition

#ifndef SEQ_LIST_H
#define SEQ_LIST_H

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAX_CAPACITY 100
typedef int elem_type;

typedef struct {
    elem_type data[MAX_CAPACITY];
    int last_idx;
} SeqList;

// Basic operations
SeqList* seq_list_create(void);
int seq_list_clear(SeqList* list);
int seq_list_is_empty(const SeqList* list);
int seq_list_get_length(const SeqList* list);
void seq_list_print(const SeqList* list);
int seq_list_free(SeqList* list);

// Core operations
elem_type seq_list_get_elem(const SeqList* list, int index);
int seq_list_locate_elem(const SeqList* list, elem_type value);
int seq_list_push_front(SeqList* list, elem_type value);
int seq_list_push_back(SeqList* list, elem_type value);
int seq_list_insert(SeqList* list, int index, elem_type value);
int seq_list_delete(SeqList* list, int index);
int seq_list_merge(SeqList* list1, const SeqList* list2);
int seq_list_remove_duplicates(SeqList* list);

#endif

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.