C语言备忘-一些数据结构和相关的算法

自己写的一些基础的C函数,如发现问题请不吝赐教。

一、循环队列。

注意对队列的任何操作都应该在list_lock_begin和list_lock_end之间

1.1 循环队列结构体定义。

index - 下一个数据append时的索引;shift - 队列填满并开始“旋转”之后最旧的那个数据的索引。

typedef int32_t y_t;
typedef uint64_t x_t;

typedef struct {
    x_t x;
    y_t y;
} XYDATA;

typedef struct {
    XYDATA *buf;
    volatile uint8_t changed;
    volatile uint8_t locked;
    volatile uint8_t cleared;
    uint32_t cnt; //data count now
    uint32_t index; //index now
    uint32_t shift; //shift count now
    uint32_t TOTAL; //total data count of this list can hold
} DataListTypeDef;

1.2 初始化。为循环队列的buffer申请空间,并初始化结构体其他元素。

输入 :dl - 要初始化的循环队列指针;total - 循环队列元素总个数;

输出:无;

void list_init(DataListTypeDef *dl, uint32_t total) {
    if (dl->buf == NULL) {
        dl->buf = (XYDATA*)malloc((total) * sizeof(XYDATA)); 
    }
    else {
        if (dl->TOTAL != total) {
            dl->buf = (XYDATA*)realloc(dl->buf, dl->TOTAL * sizeof(XYDATA));
        }
    }
    dl->locked = 0;
    dl->TOTAL = total;
    list_clear(dl);
    dl->changed = 0;
    dl->cleared = 0;
}

1.3 删除队列。释放buffer内存,并复位其他元素为默认值。

输入:dl - 队列指针;

输出:无;

void list_deinit(DataListTypeDef *dl) {
    if (dl->buf != NULL) {
        free(dl->buf);
        dl->buf = NULL;
    }
    dl->TOTAL = 0;
    dl->changed = 0;
}

1.4 队列追加一个新元素。

输入:dl - 队列指针;element - 新元素地址;

输出:无;

void list_append(DataListTypeDef *dl, XYDATA *element) {
    memcpy(&(dl->buf[dl->index]), element, sizeof(XYDATA));
    if (dl->cnt < dl->TOTAL) {
        dl->cnt++; //modify count
        dl->index++;
        if (dl->index == dl->TOTAL) { //it is full just now
            dl->index = 0;
        }
    } else { //it is full
        if (dl->index < dl->TOTAL - 1) {
            dl->index++;
        } else {
            dl->index = 0;
        }
        if (dl->shift < dl->TOTAL - 1) {
            dl->shift++;
        } else {
            dl->shift = 0;
        }
    }
    dl->changed = 1;
}

1.5 向队列追加一个子队列,同时子队列被清空

输入:dl - 源队列指针;dl_extra - 子队列地址;

void list_append_list(DataListTypeDef *dl, DataListTypeDef *dl_extra) {
    XYDATA *xy_pop;
    while (!list_is_empty(dl_extra)) {
        xy_pop = list_shift(dl_extra);
        memcpy(&(dl->buf[dl->index]), xy_pop, sizeof(XYDATA));
        if (dl->cnt < dl->TOTAL) {
            dl->cnt++; //modify count
            dl->index++;
            if (dl->index == dl->TOTAL) { //it is full just now
                dl->index = 0;
                dl->shift = 1;
            }
        } else { //it is full
            if (dl->index < dl->TOTAL - 1) {
                dl->index++;
            } else {
                dl->index = 0;
            }
            if (dl->shift < dl->TOTAL - 1) {
                dl->shift++;
            } else {
                dl->shift = 0;
            }
        }
    }
    dl->changed = 1;
}

1.6 获取指定索引的元素。

输入:dl - 队列指针;

输出:获取的元素的指针;

XYDATA* list_at(const DataListTypeDef *dl, uint32_t _index) {
    if (_index + dl->shift < dl->TOTAL) {
        return &(dl->buf[_index + dl->shift]);
    } else {
        return &(dl->buf[_index + dl->shift - dl->TOTAL]);
    }
}

1.7 获取队列中最后一个元素。

输入:dl - 队列指针;

输出:获取的元素的指针;

XYDATA* list_last(const DataListTypeDef *dl) {
    if (dl->index > 0) {
        return &(dl->buf[dl->index - 1]);
    } else {
        return &(dl->buf[dl->TOTAL - 1]);
    }
}

1.8 删除队列中的第一个元素并返回该元素的指针。

输入:dl - 队列指针;

输出:获取的元素的指针;

XYDATA *list_shift(DataListTypeDef *dl) {
    if (dl->cnt == 0) {
        return NULL;
    }

    XYDATA *xy_data = &(dl->buf[dl->shift]);
    dl->shift++;
    if (dl->shift == dl->TOTAL) {
        dl->shift = 0;
    }
    dl->cnt--;
    dl->changed = 1;

    return xy_data;
}

1.9 清除队列。实际上不清除数据buffer,只是修改结构体变量。

void list_clear(DataListTypeDef *dl) {
    dl->cnt = 0;
    dl->index = 0;
    dl->shift = 0;
    dl->changed = 1;
    dl->cleared = 1;
}

 1.10 队列上锁。这里使用sleep_ms(1)函数避免可能造成的CPU占用过高,可以根据具体场合进行修改。

void list_lock_begin(DataListTypeDef *dl) {
    while (dl->locked) {
        sleep_ms(1);
    }
    dl->locked = 1;
}

1.11 队列解锁。

void list_lock_end(DataListTypeDef *dl) {
    dl->locked = 0;
}

1.12 判断队列是否为空。

uint8_t list_is_empty(const DataListTypeDef *dl) {
    return dl->cnt == 0;
}

1.13 判断队列是否已满。

uint8_t list_is_full(const DataListTypeDef *dl) {
    return dl->cnt == dl->TOTAL;
}

1.14 获取队列当前元素数量。

uint32_t list_count(const DataListTypeDef *dl) {
    return dl->cnt;
}

1.15 清除脏标志。

void list_clear_change_flag(DataListTypeDef *dl) {
    dl->changed = 0;
}

1.16 获取脏标志。

uint8_t list_get_change_flag(const DataListTypeDef *dl) {
    return dl->changed;
}

二、FIFO。

FIFO结构体定义。注意buf这里用了char*而没有用void*,是为了计算索引位置时方便。

ipp - 数据push索引;opp - 数据pop索引;

typedef struct {
    char *buf;
    uint16_t locked;
    uint16_t ele_size;
    uint32_t ipp;
    uint32_t opp;
    uint32_t depth;
} FifoListTypeDef;

2.1 初始化。

输入:stu - FIFO指针;ele_size - buf中一个数据所占用的字节数;realloc_cnt - buf可存储的最大数据个数;

输出:无;

void fifo_init(FifoListTypeDef *stu, int ele_size, uint32_t realloc_cnt) {
    stu->ele_size = ele_size;
    stu->ipp = 0;
    stu->opp = 0;
    stu->locked = 0;
    stu->depth = realloc_cnt;
    stu->buf = (char*)malloc(stu->depth * stu->ele_size);
}

2.2 删除FIFO。释放buf空间,并初始化结构体中的其他变量。

fifo_deinit(FifoListTypeDef *stu) {
    if (stu->buf != NULL) {
        free(stu->buf);
        stu->buf = NULL;
    }
    stu->ipp = 0;
    stu->opp = 0;
}

2.3 批量添加新数据。这里使用sleep_ms(1)函数避免可能造成的CPU占用过高,可以根据具体场合进行修改。

输入:stu - fifo指针;ele_arr - 数据数组指针;cnt - 要push的数据个数;

输出:无。

void fifo_in(FifoListTypeDef *stu, void* ele_arr, uint32_t cnt) {
    while (stu->locked == 2) { //fifo clearing
        sleep_ms(1);
    }
    stu->locked = 1;
    if (stu->ipp < stu->opp) {
        if (stu->ipp + cnt >= stu->opp) { //no enough memory
            stu->locked = 0;
            return;
        }
    }
    else if (cnt >= stu->depth - stu->ipp + stu->opp) { //no enough memory
        stu->locked = 0;
        return;
    }

    if (stu->ele_size == 1) {
        if (stu->ipp + cnt <= stu->depth) { //one part
            memcpy(stu->buf + stu->ipp, ele_arr, cnt);
        } else { //two parts
            uint32_t cnt_part1 = stu->depth - stu->ipp;
            memcpy(stu->buf + stu->ipp, ele_arr, cnt_part1);
            memcpy(stu->buf, (char*)ele_arr + cnt_part1, cnt - cnt_part1);
        }
    } else {
        if (stu->ipp + cnt <= stu->depth) { //one part
            memcpy(stu->buf + stu->ele_size * stu->ipp, ele_arr, stu->ele_size * cnt);
        } else { //two parts
            uint32_t cnt_part1 = stu->depth - stu->ipp;
            memcpy(stu->buf + stu->ele_size * stu->ipp, ele_arr, stu->ele_size * cnt_part1);
            memcpy(stu->buf, (char*)ele_arr + stu->ele_size * cnt_part1, stu->ele_size * (cnt - cnt_part1));
        }
    }
    stu->ipp = (stu->ipp + cnt)%stu->depth;
    stu->locked = 0;
}

2.4 取出FIFO中的第一个数据。sleep_ms(1)说明同上。

void* fifo_out(FifoListTypeDef *stu) {
    while (stu->locked == 2) { //fifo clearing
        sleep_ms(1);
    }
    stu->locked = 1;
    char* tmp;
    if (stu->opp == stu->ipp) { //empty
        stu->locked = 0;
        return NULL;
    }
    tmp = stu->buf + stu->ele_size * stu->opp;
    stu->opp = (stu->opp + 1)%stu->depth;
    stu->locked = 0;
    return tmp;
}

2.5 取出FIFO中前4个字节数据(double word)。sleep_ms(1)说明同上。

输入:stu - fifo指针;p_data - 要存储的4字节buffer地址;

输出:无。

int fifo_out_dw(FifoListTypeDef *stu, char *p_data) {
    while (stu->locked == 2) { //fifo clearing
        sleep_ms(1);
    }
    stu->locked = 1;
    int cnt = stu->ipp - stu->opp;
    if (cnt < 0) {
        cnt += stu->depth;
    }
    if (cnt > 3) {
        *(int*)p_data = *(int*)(stu->buf + stu->opp);
        stu->opp = (stu->opp + 4)%stu->depth;
        stu->locked = 0;
        return 4;
    }
    stu->locked = 0;
    return 0;
}

2.6 清除fifo。实际上不清除数据buffer,只是修改结构体变量。

void fifo_clear(FifoListTypeDef *stu) {
    while (stu->locked) {
        sleep_ms(1);
    }
    stu->locked = 2;
    stu->ipp = 0;
    stu->opp = 0;
    stu->locked = 0;
}

三、双向链表。

该双向链表结构如下图。其中head->prev指向tail,这样可以通过head快速找到tail,方便进行尾插节点。

 节点数据结构定义如下。

typedef struct _linklist {
    void *buf;
    struct _linklist *prev;
    struct _linklist *next;
} LinkListTypeDef;

3.1 链表初始化。

输入:pp_head - 指向链表头指针的指针。注意要修改的主体是指针本身,因此要传入二级指针。

输出:无。

void linklist_init(LinkListTypeDef **pp_head) {
    *pp_head = NULL;
}

3.2 删除链表。释放所有节点空间。

void linklist_deinit(LinkListTypeDef **pp_head) {
    LinkListTypeDef *p = (*pp_head);
    LinkListTypeDef *p_next;
    while (p != NULL) {
        p_next = p->next;
        free(p);
        p = p_next;
    }
    *pp_head = NULL;
}

3.3 添加节点(尾插法)。注意:1)ele不是节点指针而只是节点的数据指针,也就是节点的buf,下同;2)malloc的节点数据指针只是指向ele指向的内存区域,而没有进行深拷贝,如果需要进行深拷贝请将buf也malloc一份(但要知道malloc空间大小)然后memcpy。

输入:pp_head - 指向头指针的指针;ele - 要添加的节点数据

void linklist_append(LinkListTypeDef **pp_head, void* ele) {
    if (*pp_head == NULL) {
        *pp_head = (LinkListTypeDef *)malloc(sizeof(LinkListTypeDef));
        (*pp_head)->buf = ele;
        (*pp_head)->prev = *pp_head; //NOTE: *pp_head->prev pointer to linklist tail
        (*pp_head)->next=NULL;
        return;
    }

    LinkListTypeDef *p_tail = (*pp_head)->prev; //it is linklist tail
    p_tail->next = (LinkListTypeDef *)malloc(sizeof(LinkListTypeDef));
    p_tail->next->buf = ele;
    p_tail->next->prev = p_tail;
    p_tail->next->next = NULL;
    (*pp_head)->prev = p_tail->next; //NOTE
}

3.4 添加节点(任意位置)。

输入:pp_head - 指向头指针的指针;ele - 要添加的节点数据指针;ele_after - 要插入的位置处的节点数据指针(ele添加到ele_after原来的位置,ele_after后移成为ele->next);

输出:无。

void linklist_insert(LinkListTypeDef **pp_head, void* ele, void* ele_after) {
    if (ele_after == NULL) {
        linklist_append(pp_head, ele);
        return;
    }

    LinkListTypeDef *p = (*pp_head);
    while (p != NULL && p->buf != ele_after) {
        p = p->next;
    }
    if (p == NULL) { //not find ele_after, so append ele to linklist end
        linklist_append(pp_head, ele);
        return;
    }

    LinkListTypeDef *p_prev = p->prev;
    LinkListTypeDef *p_insert = (LinkListTypeDef *)malloc(sizeof(LinkListTypeDef));
    p_insert->buf = ele;
    p_insert->prev = p_prev;
    p_insert->next = p;
    p->prev = p_insert;
    if (p != (*pp_head)) {
        p_prev->next = p_insert;
    }
}

3.5 删除数据ele对应的节点。

void linklist_remove(LinkListTypeDef **pp_head, void* ele) {
    LinkListTypeDef *p = (*pp_head);
    while (p != NULL && p->buf != ele) {
        p = p->next;
    }
    if (p != NULL) { //find ele in linklist
        LinkListTypeDef *p_prev = p->prev;
        if (p != (*pp_head)) {
            p_prev->next = p->next;
            if (p->next != NULL) {
                p->next->prev = p_prev;
            } else { //linklist tail
                (*pp_head)->prev = p->prev; //NOTE
            }
        } else { //p_head is just the element to delete
            if (p->next != NULL) { //list count more than 1
                p->next->prev = p_prev;
            }
            *pp_head = p->next;
        }
        free(p);
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值