Home > OS >  How to store array of linked lists in a binary file?
How to store array of linked lists in a binary file?

Time:04-25

I would like to save an array of linked lists in a binary file, but I don't know how to assign the dynamic memory due to the varying lengths of linked lists for each bucket.

And to access a random position containing the whole linked list without reading the whole file, like a kind of index file? Some tip?

CodePudding user response:

I will make these assumptions:

  • Every (non-“null”) element of each list is an int
  • There are MAX_INT or fewer elements in each list

Make your file (remember to open in binary mode) have the following structure:

  • Output an int containing the number of items in the first list
  • Output each int in that list
  • Repeat for each subsequent list

This scheme has two drawbacks:

  • each list has a (large) maximum number of elements
  • you must traverse each list twice to save (first to learn the length, again to save each item)

It has the advantage of being very quick and direct to load.

CodePudding user response:

here is a simple code,you can use fwrite to file and fread from file as you wish,but you must consider the big-endian or little-endian

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

typedef struct _Node {
    struct _Node *next;
    int val;
} Node;

void serialize(Node arr[], int size[], int len) {

    FILE *f = fopen("serialize.bin", "wb");
    //write arr len
    fwrite(&len, sizeof(int), 1, f);
    //write array
    for (int i = 0; i < len;   i) {
        //write linklist len
        fwrite(&size[i], sizeof(int), 1, f);
        Node *tmp = &arr[i];
        while (tmp) {
            fwrite(&tmp->val, sizeof(int), 1, f);
            tmp = tmp->next;
        }
    }
    fclose(f);
}

Node *deserialize() {

    FILE *f = fopen("serialize.bin", "rb");
    int len;
    fread(&len, sizeof(int), 1, f);
    Node *ret = malloc(len * sizeof(Node));

    for (int i = 0; i < len;   i) {
        int linklen;
        int val;
        Node *tmp = &ret[i];
        fread(&linklen, sizeof(int), 1, f);
        fread(&val, sizeof(int), 1, f);
        ret[i].val = val;
        ret[i].next = NULL;
        linklen--;

        while (linklen--) {
            fread(&val, sizeof(int), 1, f);
            tmp->next = malloc(sizeof(Node));
            tmp->next->next = NULL;
            tmp->next->val = val;
            tmp = tmp->next;
        }
    }

    return ret;
}


int main() {
#define ARRAY_LEN 3
    Node arr[ARRAY_LEN];
    int size[ARRAY_LEN];

    arr[0].next = malloc(sizeof(Node));
    arr[0].val = 1;
    arr[0].next->next = malloc(sizeof(Node));
    arr[0].next->val = 2;
    arr[0].next->next->next = NULL;
    arr[0].next->next->val = 3;
    size[0] = 3;

    arr[1].next = malloc(sizeof(Node));
    arr[1].val = 11;
    arr[1].next->next = NULL;
    arr[1].next->val = 22;
    size[1] = 2;

    arr[2].next = NULL;
    arr[2].val = 33;
    size[2] = 1;

    serialize(arr, size, ARRAY_LEN);

    Node *ret = deserialize();
    //TODO free memory

    return 0; //end of code
}

CodePudding user response:

The solution is not very complicated if there is a value that is never stored as an element in your linked list-- in that case, you can treat the linked list like a glorified null-terminated string, where whatever value that cannot exist in the linked list acts as the terminator. If you don't have such luxury, then you can write an extra byte with each value that determines if the value is the last one or not. Here's an implementation of the first possible solution, though it can be easily modified to work in the case of the second:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define NODE_V_SIZE sizeof(int)

const int list_end = -1;

typedef struct Node {
    int value;
    struct Node *prev, *next;
} Node;

void free_nodes(Node *head) {
    while (head) {
        Node *to_free = head;
        head = head->next;
        free(to_free);
    }
}

Node* new_node(int value) {
    Node *node = malloc(sizeof(Node));
    if (!node) {
        return NULL;
    }
    node->prev = NULL;
    node->next = NULL;
    node->value = value;
    return node;
}

int write_nodes(int fd, Node *head) {
    while (head) {
        if (write(fd, &head->value, NODE_V_SIZE) != NODE_V_SIZE) {
            return -1;
        }
        head = head->next;
    }
    if (write(fd, &list_end, NODE_V_SIZE) != NODE_V_SIZE) {
        return -1;
    }
    return 0;
}

Node* read_nodes(int fd) {
    Node *head = NULL;
    Node *cur = NULL;
    int in;
    while (1) {
        if (read(fd, &in, NODE_V_SIZE) != NODE_V_SIZE) {
            free_nodes(head);
            return NULL;
        }
        if (in == list_end) {
            return head;
        }
        if (cur) {
            cur->next = new_node(in);
            if (!cur->next) {
                free_nodes(head);
                return NULL;
            }
            cur->next->prev = cur;
            cur = cur->next;
        } else {
            cur = new_node(in);
            if (!cur) {
                return NULL;
            }
            head = cur;
        }
    }
}

Node* new_random_list(int modifier) {
    Node *head = new_node(0);
    if (!head) {
        printf("out of memory\n");
        exit(1);
    }
    Node *cur = head;
    
    for (int i = 0; i < 10; i  ) {
        cur->next = new_node((i modifier)*3);
        if (!cur->next) {
            free_nodes(head);
            printf("out of memory\n");
            exit(1);
        }
        cur = cur->next;
    }
    
    return head;
}

int main() {
#define NHEADS 10
    // open file
    int fd = open("dat", O_RDWR);
    if (fd == -1) {
        printf("failed to open file\n");
        exit(1);
    }

    // make NHEADS number of 10 nodes linked together and write them to fd
    for (int i = 0; i < NHEADS; i  ) {
        Node *head = new_random_list(i);
        if (write_nodes(fd, head)) {
            printf("failed to serialize nodes\n");
            exit(1);
        }
        free_nodes(head);
    }
    
    // read from fd to populate got then print it, repeat NHEADS times
    lseek(fd, 0, SEEK_SET);
    for (int i = 0; i < NHEADS; i  ) {
        Node *got = read_nodes(fd);
        if (!got) {
            printf("failed to deserialize nodes\n");
            exit(1);
        }
        Node *head = got;
        
        while (got) {
            printf("%d\n", got->value);
            got = got->next;
        }
        printf("\n");
        
        free_nodes(head);
    }
    close(fd);
    
    return 0;
}
  • Related