C数据结构
Posted mChenys
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C数据结构相关的知识,希望对你有一定的参考价值。
目录
一、动态数组
所谓动态数组就是可以自动扩容的数组, 例如:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//动态数组
struct DynamicArray
//数组存储元素的空间首地址,存放的都是地址void*
void **addr;
//最大容量
int capacity;
//实际的元素个数
int size;
;
//初始化
struct DynamicArray *Init_DynamicArray(int capacity)
if (capacity < 0)
return NULL;
// 创建动态数组的指针并分配空间
struct DynamicArray *arr = malloc(sizeof(struct DynamicArray));
// 初始化数组初始元素的空间
arr->addr = malloc(capacity * sizeof(void *));
// 初始容量
arr->capacity = capacity;
// 实际的元素个数
arr->size = 0;
return arr;
//在指定位置插入元素,如果该位置大于末尾元素的位置,则直接插入到末尾元素之后
void Inseart_DynamicArray(struct DynamicArray *arr, int index, void *value)
if (NULL == arr)
return;
if (index <= 0)
return;
// 如果新增的元素位置大于当前元素末尾位置,则直接插入到末尾位置
if (index > arr->size)
index = arr->size;
if (arr->size >= arr->capacity)
// 如果当前元素个数大于当前容量,需要进行扩容,在之前的容量上扩大一倍
int new_capacity = arr->capacity * 2;
void **new_addr = malloc(new_capacity * sizeof(void *));
//拷贝原来的数据到新地址上
memcpy(new_addr, arr->addr, arr->capacity * sizeof(void *));
//释放旧地址
free(arr->addr);
//更新新地址
arr->addr = new_addr;
//更新容量
arr->capacity = new_capacity;
//将原生插入到index位置
//插入前需要将index位置之后的所有元素需要移动,从尾巴开始向后逐个元素移动一位,腾出位置来放置index的元素
for (int i = arr->size - 1; i >= index; --i)
//让后一个位置等于前一个元素即可
arr->addr[i + 1] = arr->addr[i];
//最后将value插入到index位置
arr->addr[index] = value;
//更新元素个数
arr->size++;
//遍历
void Foreach_DynamicArray(struct DynamicArray *arr, void (*_callback)(void *))
if (NULL == arr)
return;
if (NULL == _callback)
return;
for (int i = 0; i < arr->size; ++i)
_callback(arr->addr[i]);
//按位置删除
void Remove_By_Index(struct DynamicArray *arr, int index)
if (NULL == arr)
return;
if (index < 0 || index > arr->size - 1)
return;
for (int i = index; i < arr->size; ++i)
//将后一个元素覆盖前一个元素即可
arr->addr[i] = arr->addr[i + 1];
//更新size
arr->size--;
//按值删除
void Remove_By_Value(struct DynamicArray *arr, void *value, int (*compare)(void *, void *))
if (NULL == arr || NULL == value || NULL == compare)
return;
for (int i = 0; i < arr->size; ++i)
//因为无法确定数据类型,所以通过回调函数处理比较
if (compare(arr->addr[i], value))
Remove_By_Index(arr, i);
break;
//销毁
void Destory_DynamicArray(struct DynamicArray *arr)
if (NULL == arr)
return;
if (NULL != arr->addr)
free(arr->addr);
arr->addr = NULL;
free(arr);
arr = NULL;
使用方式如下:
//定义存放的元素
struct Person
char name[64];
int age;
;
//打印值得回调函数
void my_callback(void *data)
if (NULL == data)
return;
struct Person *p = (struct Person *)data;
printf("name=%s,age=%d\\n", p->name, p->age);
//比较2个值是否相等的回调函数
int value_compare(void *d1, void *d2)
struct Person *p1 = (struct Person *)d1;
struct Person *p2 = (struct Person *)d2;
return strcmp(p1->name, p2->name) == 0 && p1->age == p2->age;
int main()
struct DynamicArray *arr = Init_DynamicArray(5);
struct Person p1 = "aaa", 10;
struct Person p2 = "bbb", 20;
struct Person p3 = "ccc", 30;
struct Person p4 = "ddd", 40;
struct Person p5 = "eee", 50;
struct Person p6 = "fff", 60;
Inseart_DynamicArray(arr, 10, &p1);
Inseart_DynamicArray(arr, 10, &p2);
Inseart_DynamicArray(arr, 10, &p3);
Inseart_DynamicArray(arr, 10, &p4);
Inseart_DynamicArray(arr, 10, &p5);
printf("扩容前capacity:%d\\n", arr->capacity);
Inseart_DynamicArray(arr, 10, &p6);
printf("扩容后capacity:%d\\n", arr->capacity);
Foreach_DynamicArray(arr, my_callback);
printf("删除index=2的元素\\n");
Remove_By_Index(arr, 2);
printf("删除后的数组为:\\n");
Foreach_DynamicArray(arr, my_callback);
printf("按值删除 aaa, 10 \\n");
struct Person p_del = "aaa", 10;
Remove_By_Value(arr, &p_del, value_compare);
printf("删除后的数组为:\\n");
Foreach_DynamicArray(arr, my_callback);
system("pause");
return 0;
输出结果:
扩容前capacity:5
扩容后capacity:10
name=aaa,age=10
name=bbb,age=20
name=ccc,age=30
name=ddd,age=40
name=eee,age=50
name=fff,age=60
删除index=2的元素
删除后的数组为:
name=aaa,age=10
name=bbb,age=20
name=ddd,age=40
name=eee,age=50
name=fff,age=60
按值删除 aaa, 10
删除后的数组为:
name=bbb,age=20
name=ddd,age=40
name=eee,age=50
name=fff,age=60
二、单向链表
有2种方案,分别是将数据保存到链表节点中和将链表节点保存到数据中,下面会分别介绍
方案一:
先创建链表的头文件LinkList.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C"
#endif
// 定义类型
// 用LinkList替代void*,可以将struct LList保户起来(struct LList定义在实现文件中,它代表链表本身),不让外界看到.
typedef void *LinkList;
typedef void(FOREACH_CALLBACK)(void *); //遍历的回调函数
typedef int(COMPARE_CALLBACK)(void *, void *); // 对比的回调函数
//初始化
LinkList Init_LinkList();
//遍历
void Foreach_LinkList(LinkList list, FOREACH_CALLBACK callback);
//插入
void Inseart_LinkList(LinkList list, int index, void *value);
//根据位置删除
void Remove_By_Index(LinkList list, int index);
//根据值删除
void Remove_By_Value(LinkList list, void *value, COMPARE_CALLBACK callback);
//清空列表
void Clear_LinkList(LinkList list);
//销毁
void Destory_LinkList(LinkList list);
//元素个数
int Size_Of_LinkList(LinkList list);
#ifdef __cplusplus
#endif
创建链表的实现文件LinkList.c
#include "LinkList.h"
// 代表链表内每个元素的节点结构体
struct LinkNode
void *addr; //存放数据的地址
struct LinkNode *next;
;
// 链表的结构体
struct LList
struct LinkNode header; // 头结点
int size;
;
// 初始化
LinkList Init_LinkList()
struct LList *list = malloc(sizeof(struct LList));
struct LinkNode header;
header.addr = NULL;
header.next = NULL;
list->header = header;
list->size = 0;
return list;
// 遍历
void Foreach_LinkList(LinkList linkList, FOREACH_CALLBACK callback)
if (NULL == linkList)
return;
struct LList *list = (struct LList *)linkList;
struct LinkNode *curr_node = list->header.next;
while (NULL != curr_node)
// 从头节点的next节点开始遍历
callback(curr_node->addr);
// 更新当前node
curr_node = curr_node->next;
// 按位置插入元素
void Inseart_LinkList(LinkList linkList, int index, void *value)
if (NULL == linkList || NULL == value)
return;
// 先强转成内部链表结构体指针类型
struct LList *list = (struct LList *)linkList;
// 得到头结点的结构体指针
struct LinkNode *curr_node = &(list->header);
if (index < 0 || index > list->size)
index = list->size;
//查找要插入的节点的前一个节点
for (int i = 0; i < index; ++i)
// 先获取到index的前一个节点
curr_node = curr_node->next;
// 创建新节点
struct LinkNode *new_node = malloc(sizeof(struct LinkNode));
new_node->addr = value;
new_node->next = NULL;
// 将当前节点的next节点给新节点的next
new_node->next = curr_node->next;
// 修改当前节点的next节点指向新添加的节点
curr_node->next = new_node;
// 更新个数
list->size++;
// 根据位置删除
void Remove_By_Index(LinkList linkList, int index)
if (NULL == linkList)
return;
struct LList *list = (struct LList *)linkList;
if (index < 0 || index > list->size - 1)
return;
//先找到要删除节点的前一个节点
struct LinkNode *curr_node = &(list->header);
for (int i = 0; i < index; ++i)
// 先获取到index的前一个节点
curr_node = curr_node->next;
//修改当前节点的next为要删除节点的next
struct LinkNode *del_node = curr_node->next;
curr_node->next = del_node->next;
//释放删除节点的空间
free(del_node);
del_node = NULL;
//更新个数
list->size--;
// 根据值删除
void Remove_By_Value(LinkList linkList, void *value, COMPARE_CALLBACK callback)
if (NULL == linkList || NULL == callback || NULL == value)
return;
struct LList *list = (struct LList *)linkList;
// curr_node的上一个节点
struct LinkNode *pre_node = &(list->header);
// curr_node就是要被删除的节点
struct LinkNode *curr_node = pre_node->next;
while (curr_node != NULL)
if (callback(curr_node->addr, value))
break;
pre_node = curr_node;
// 不断的更新curr_node
curr_node = curr_node->next;
if (curr_node == NULL) //没有找到
return;
//删除当前节点
pre_node->next = curr_node->next;
free(curr_node);
curr_node = NULL;
//更新个数
list->size--;
//还要一种方式是使用for循环找到要删除元素的index,然后调用Remove_By_Index
/*struct LinkNode* curr_node = &(list->header);
for (int i = 0; i < list->size; ++i)
curr_node = curr_node->next;
if (callback(curr_node->addr, value))
Remove_By_Index(linkList, i);
break;
*/
// 清空列表
void Clear_LinkList(LinkList linkList)
if (NULL == linkList)
return;
struct LList *list = (struct LList *)linkList;
struct LinkNode *curr_node = list->header.next;
while (NULL != curr_node)
//先保存下一个节点
struct LinkNode *next_node = curr_node->next;
//释放当前节点
free(curr_node);
curr_node = next_node;
list->size = 0;
list->header.<以上是关于C数据结构的主要内容,如果未能解决你的问题,请参考以下文章