[C语言]2D-linked list(二维链表)

[C语言]2D-linked list-二维链表


不多BB,直接上图,我们要实现如下的矩阵形状的二维列表

    head -----------+   NULL              NULL
                    |    ^                 ^
                    |    |                 |
                    v    |                 |
                  +---------+         +---------+
    NULL <--------|    1    |<------->|    2    |------> NULL
                  +---------+         +---------+
                       ^                   ^ 
                       |                   |
                       v                   v
                  +---------+         +---------+
    NULL <--------|    3    |<------->|    4    |------> NULL
                  +---------+         +---------+
                       |                 |    ^
                       |                 |    |
                       v                 v    +--------- tail
                      NULL              NULL

Figure 1

头文件

#ifndef _DOUBLL2D_H
#define _DOUBLL2D_H

/* Header file for a 2d doubly linked list. */

#include <stdbool.h>
#include <stddef.h>

/* A list element (doubll2d_elem) has pointers to the four elements around it
   (i.e. left, right, up and down). The pointer should point to NULL if the
   neighbor it points to doesn't exist.

   It also has a pointer to the data (owned by the list element) and the size of
   that data. */

typedef struct doubll2d_elem doubll2d_elem;

struct doubll2d_elem
{
   
   doubll2d_elem *left;
   doubll2d_elem *right;
   doubll2d_elem *up;
   doubll2d_elem *down;

   void *data;
   size_t size;
};

typedef struct doubll2d doubll2d;

/*
   You can imagine that our 2D linked list is a matrix, which MUST have
   a shape of rectangular at all time.

   The 2D doubly linked list with 4 elements (2 by 2) is like this:

    head -----------+   NULL              NULL
                    |    ^                 ^
                    |    |                 |
                    v    |                 |
                  +---------+         +---------+
    NULL <--------|    1    |<------->|    2    |------> NULL
                  +---------+         +---------+
                       ^                   ^ 
                       |                   |
                       v                   v
                  +---------+         +---------+
    NULL <--------|    3    |<------->|    4    |------> NULL
                  +---------+         +---------+
                       |                 |    ^
                       |                 |    |
                       v                 v    +--------- tail
                      NULL              NULL

    An empty list looks like this:

    head ------> NULL
    NULL <------ tail

    (If not empty) The head pointer of a list should always point to the
    upper-left most element, and the tail pointer should always point to the
    lower-right most element.

    The dim_row and dim_col stores the dimension of the rows and columns (i.e.
    the number of rows and columns).
*/
struct doubll2d
{
   
   doubll2d_elem *head;
   doubll2d_elem *tail;

   size_t dim_row;
   size_t dim_col;
};

/* Initialize a 2D doubly linked list. */
void doubll2d_init(doubll2d *list);

/* Return the upper-left most element of the list.
   Return NULL on error. */
doubll2d_elem *doubll2d_get_head(doubll2d *list);

/* Return the lower-right most element of the list.
   Return NULL on error. */
doubll2d_elem *doubll2d_get_tail(doubll2d *list);

/* Return number of rows in a list.
   Return -1 on error. */
size_t doubll2d_dim_row(doubll2d *list);

/* Return number of columns in a list.
   Return -1 on error. */
size_t doubll2d_dim_col(doubll2d *list);

/* Insert a new row in the list below the row where the given `cursor` locates.
   The given `data` should be **copied** to the newly created elements.
   The `length` is the number of data pointers given to you.
   Return the pointer to the newly created element below the given `cursor`.
   Return NULL on error.

   Remember, our 2D doubly linked list should always be a rectangular. So if
   the `length` is shorter than it should be, abort immediately and return NULL.
   However, it is okay that the `length` is longer than needed. And in this case
   you should make use of the first `doubll.dim_col` items in `data` and leave
   alone the rest.

   If the marco CHECK_LIST is set, your code has to check if the element `cursor` is
   actually a member of the list. If not, abort and return NULL. This check is slow. 
   If the marco CHECK_LIST is not set, your code shall not perform that check
   but rather run very fast. */
doubll2d_elem *doubll2d_insert_row(doubll2d *list, doubll2d_elem *cursor,
                                   void **data, size_t *size, size_t length);

/* Insert a new column in the list after the column where the given `cursor`
   locates. The given `data` should be **copied** to the newly created elements.
   The `length` is the number of data pointers given to you.
   Return the pointer to the newly created element after the given `cursor`.
   Return NULL on error.

   Remember, our 2D doubly linked list should always be a rectangular. So if
   the `length` is shorter than it should be, abort immediately and return NULL.
   However, it is okay that the `length` is longer than needed. And in this case
   you should make use of the first `doubll.dim_row` items in `data` and leave
   alone the rest.

   If the marco CHECK_LIST is set, your code has to check if the element `cursor` is
   actually a member of the list. If not, abort and return NULL. This check is slow. 
   If the marco CHECK_LIST is not set, your code shall not perform that check
   but rather run very fast. */
doubll2d_elem *doubll2d_insert_col(doubll2d *list, doubll2d_elem *cursor,
                                   void **data, size_t *size, size_t length);

/* Delete the row where the given `cursor` locates and returns the element above
   the given `cursor`. If the first row is deleted, then return the element
   below the given `cursor`. If the deleted row is the only row in the list,
   return NULL. Return NULL on error.

   If the marco CHECK_LIST is set, your code has to check if the element `cursor` is
   actually a member of the list. If not, abort and return NULL. This check is slow. 
   If the marco CHECK_LIST is not set, your code shall not perform that check
   but rather run very fast. */
doubll2d_elem *doubll2d_delete_row(doubll2d *list, doubll2d_elem *cursor);

/* Delete the column where the given `cursor` locates and returns the element
   before the given `cursor`. If the first column is deleted, then return the
   element after the given `cursor`. If the deleted column is the only column in
   the list, return NULL. Return NULL on error.

   If the marco CHECK_LIST is set, your code has to check if the element `cursor` is
   actually a member of the list. If not, abort and return NULL. This check is slow. 
   If the marco CHECK_LIST is not set, your code shall not perform that check
   but rather run very fast. */
doubll2d_elem *doubll2d_delete_col(doubll2d *list, doubll2d_elem *cursor);

/*  Purge all items from the list. */
void doubll2d_purge(doubll2d *list);

/* Compare function between two list elements. Return true if `a` is less than `b`.
   You could implement your own compare function in your test file. */
typedef bool list_less_func(const doubll2d_elem *a, const doubll2d_elem *b);

/* Use the given `less` function to find the maximum element in the whole list.
   If there are multiple maximum elements, return any one of them.
   When the 2D linked list is empty, return NULL.
 */
doubll2d_elem *doubll2d_find_max(doubll2d *list, list_less_func *less);

/* Use the given `less` function to find the minimum element in the whole list.
   If there are multiple minimum elements, return any one of them.
   When the 2D linked list is empty, return NULL.
 */
doubll2d_elem *doubll2d_find_min(doubll2d *list, list_less_func *less);

#endif /* doubll2d.h */

.C文件

#include "doubll2d.h"
#ifndef CHECK_LIST
#define CHECK_LIST false
#endif 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void doubll2d_init(doubll2d *list)
{
   
    list->head = NULL; 
    list->tail = NULL;
    list->dim_col = 0;
    list->dim_row = 0;
}
doubll2d_elem *doubll2d_get_head(doubll2d *list)
{
   
    if (list == NULL)
    {
   
        return NULL;
    }
    return list->head; 
}

doubll2d_elem *doubll2d_get_tail(doubll2d *list)
{
   
    if (list == NULL) 
    {
   
        return NULL; 
    }
    return list->tail; 
}

size_t doubll2d_dim_row(doubll2d *list)
{
   
    if (list == NULL) 
    {
   
        return -1;
    }
    return list->dim_row; 
}

size_t doubll2d_dim_col(doubll2d *list)
{
   
    if (list == NULL) 
    {
   
        return -1;
    }
    return list->dim_col; 
}

bool check(doubll2d *list, doubll2d_elem *cursor) /*gurantee list and cursor to be not empty*/
{
   
    doubll2d_elem *p = list->head; 
    doubll2d_elem *this_row = list->head;
    size_t i = 0;
    size_t j = 0;
    if (CHECK_LIST) 
    {
   
        for (i = 0; i < list->dim_row; i++) 
        {
   
            for (j = 0; j < list->dim_col; j++)
            {
   
                if (j == list->dim_col - 1 && i != list->dim_row - 1)
                    this_row = p->down;
                if (i % 2 == 0)
                {
   
                    if (cursor == p)
                        return true; 
                    p = p->right;
                }
                else
                {
   
                    if (cursor == p)
                        return true; 
                    p = p->left;
                }
            }
            p = this_row; 
        }
        return false;
    }
    return true; 
}
bool set_list(doubll2d *list, void **data, size_t *size) /*call only when the list is empty and cursor is NULL*/
{
   
    if (list->dim_col == 0 || list->dim_row == 0) /*empty list*/
    {
   
        doubll2d_elem *first = malloc(sizeof(doubll2d_elem));
        list->dim_col = 1;
        list->dim_row = 1;                     
        first->data = (void *)malloc(size[0]); 
        memcpy(first->data, data[0], size[0]);
        first->size = size[0]; 
        first->left = NULL;    
        first->right = NULL;
        first->up = NULL; 
        first->down = NULL;
        list->head = first;
        list->tail = first; 
        return true;
    }
    return false; /*not empty*/
}

doubll2d_elem *doubll2d_insert_row(doubll2d *list, doubll2d_elem *cursor, void **data, size_t *size, size_t length)
{
   
    doubll2d_elem *result; 
    size_t i = 0;
    bool tag = true;
    if(list==NULL)return NULL;/*first list==NULL second list not NULL but cursor NULL third list not NULL cursor not NULL*/
    if(list->head==NULL&&cursor!=NULL)return NULL;
    if(list->head==NULL&&cursor==NULL)
    {
   
        set_list(list,data,size);
        return list->head;
    }
    if (!check(list,cursor))return NULL; 
    if (cursor->down == NULL)tag = false;
    if (length < list->dim_col) return NULL;      
    if (length >= list->dim_col) 
    {
   
        doubll2d_elem *this_row = cursor;
        while (this_row->left != NULL) 
        {
   
            this_row = this_row->left; /*reach top*/
        }
        for (i = 0; i < list->dim_col; i++)
        {
   
            doubll2d_elem *ptr = malloc(
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值