动态数组和链表

动态数组

  • 设计一个动态数据, 实现存储任意数据类型
  • 并有遍历, 插入, 删除数据等功能

动态数组的设计

动态数组结构体

// 动态数组结构体
struct dynamicArray
{
	// 真实在堆区开辟数组的指针
	void** pAddr;
	// 数组容量
	int m_Capacity;
	// 数组大小
	int m_Size;
};

初始化数组

// 初始化数组
// capacity: 数组的初始大小
struct dynamicArray* init_dynamicArray(int capacity)
{
	if (capacity <= 0)
	{
		return NULL;
	}

	struct dynamicArray* arr = malloc(sizeof(struct dynamicArray));
	if (arr == NULL)
	{
		return NULL;
	}

	// 给属性初始化
	arr->pAddr = malloc(sizeof(void*) * capacity);
	// 容量初始化
	arr->m_Capacity = capacity;
	// 大小初始化
	arr->m_Size = 0;

	return arr;
}

插入数据

// 插入数据
// arr: 动态数组地址
// data: 要插入的数据
// pos: 要插入的位置
void insert_dynamicArray(struct dynamicArray* arr, void* data, int pos)
{
	if (arr == NULL || data == NULL)
	{
		return;
	}

	if (pos < 0 || pos > arr->m_Size)
	{
		pos = arr->m_Size;
	}

	// 判断数组是否满了
	if (arr->m_Size == arr->m_Capacity)
	{
		// 1. 计算新空间大小
		int newCapacity = arr->m_Capacity * 2;

		// 2. 开辟新空间
		void** newSpace = malloc(sizeof(void*) * newCapacity);

		// 3. 将原来空间数据拷贝到新空间
		memcpy(newSpace, arr->pAddr, sizeof(void*)* arr->m_Capacity);

		// 4. 释放原来空间
		free(arr->pAddr);

		// 5. 更改指针指向
		arr->pAddr = newSpace;

		// 6. 更新新容量
		arr->m_Capacity = newCapacity;
	}

	// 将元素插入数组中指定位置

	// 将pos以后的元素往后移动
	for (int i = arr->m_Size-1; i >= pos; i--)
	{
		arr->pAddr[i + 1] = arr->pAddr[i];
	}
	
	// 将数据插入到指定位置
	arr->pAddr[pos] = data;

	//更新数组大小
	arr->m_Size++;
}

按照指定位置删除数组

// 按照指定位置删除数组
// pos : 指定的位置
void removeByPos_dynamicArray(struct dynamicArray* arr, int pos)
{
	if (arr == NULL)
	{
		return;
	}

	if (pos < 0 || pos > arr->m_Size - 1)
	{
		// 无效位置, return
		return;
	}
	
	// 删除指定位置元素, 从前往后移动
	for (int i = pos; i < arr->m_Size; i++)
	{
		arr->pAddr[i] = arr->pAddr[i + 1];
	}

	// 更新数组的大小
	arr->m_Size--;

}

按值比较删除数据

// 按值比较删除数据
void removeByValue_dynamicArray(struct dynamicArray* arr, void* data, int(*myCompare)(void*,void*))
{
	if (arr == NULL || data == NULL)
	{
		return;
	}

	for (int i = 0; i < arr->m_Size; i++)
	{
		if (myCompare(arr->pAddr[i],data))
		{
			removeByPos_dynamicArray(arr, i);
			break;
		}
	}
}

销毁数组

// 销毁数组
void destroy_dynamicArray(struct dynamicArray* arr)
{
	if (arr == NULL)
	{
		return;
	}

	// 内部维护在堆区数组指针相释放
	if (arr->pAddr != NULL)
	{
		free(arr->pAddr);
		arr->pAddr = NULL;
	}

	free(arr);
	arr = NULL;

}

测试

测试结构体类型

struct Person
{
	char name[64];
	int age;
};

回调函数

// 回调函数 打印输出
void printPerson(void* data)
{
	struct Person* p = data;
	printf("name: %s, age: %d\n", p->name, p->age);
}
// 回调函数 对比删除数据
int comparePerson(void* data1, void* data2)
{
	struct Person* p1 = data1;
	struct Person* p2 = data2;

	if (strcmp(p1->name,p2->name) == 0 && p1->age == p2->age)
	{
		return 1;
	}

	return 0;
}

测试主程序

// 测试动态数组
void test01()
{
	// 初始化动态数组
	struct dynamicArray* arr = init_dynamicArray(5);

	struct Person p1 = { "aaa",18 };
	struct Person p2 = { "bbb",19 };
	struct Person p3 = { "ccc",16 };
	struct Person p4 = { "ddd",13 };
	struct Person p5 = { "eee",14 };
	struct Person p6 = { "fff",20 };

	printf("插入前------数组的大小: %d\n", arr->m_Size);
	printf("插入前------数组的容量: %d\n", arr->m_Capacity);

	// 插入数据
	insert_dynamicArray(arr, &p1, 0);
	insert_dynamicArray(arr, &p2, 6);
	insert_dynamicArray(arr, &p3, 2);
	insert_dynamicArray(arr, &p4, 1);
	insert_dynamicArray(arr, &p5, -1);
	insert_dynamicArray(arr, &p6, 4);

	// aaa ddd bbb ccc fff eee
	foreach_dynamicArray(arr, printPerson);

	printf("插入后------数组的大小: %d\n", arr->m_Size);
	printf("插入后------数组的容量: %d\n", arr->m_Capacity);

	// 删除 "ddd" 
	removeByPos_dynamicArray(arr, 1);

	printf("删除ddd后的结果:\n");
	foreach_dynamicArray(arr, printPerson);

	printf("删除后------数组的大小: %d\n", arr->m_Size);
	printf("删除后------数组的容量: %d\n", arr->m_Capacity);


	// 删除 "ccc" 
	struct Person p = { "ccc",16 };
	removeByValue_dynamicArray(arr, &p, comparePerson);

	printf("删除ccc后的结果:\n");
	foreach_dynamicArray(arr, printPerson);

	printf("删除后------数组的大小: %d\n", arr->m_Size);
	printf("删除后------数组的容量: %d\n", arr->m_Capacity);

	// 测试销毁
	destroy_dynamicArray(arr);
	arr = NULL;
}

单向链表-传统版

链表设计

节点结构体

  • 数据域
  • 指针域
struct LinkNode
{
	//数据域
	void* data;
	// 指针域
	struct LinkNode* next;
};

链表结构体

  • 头节点
  • 链表长度
struct LList
{
	// 头节点
	struct LinkNode pHeader;
	// 链表长度
	int m_Size;
};

给到用户的是: void* 取别名 LinkList

typedef void* LinkList;

初始化链表

LinkList init_LinkList()
{
	// 分配内存
	struct LList* mylist = malloc(sizeof(struct LList));

	if (mylist == NULL)
	{
		return NULL;
	}

	// 给头节点属性初始化
	mylist->pHeader.data = NULL;
	mylist->pHeader.next = NULL;
	mylist->m_Size = 0;

	return mylist;
}

插入节点

void insert_LinkList(LinkList list, int pos, void* data)
{
	if (list == NULL)
	{
		return;
	}
	if (data == NULL)
	{
		return;
	}

	struct LList* mylist = list;

	if (pos < 0 || pos > mylist->m_Size )
	{
		// 无效位置
		pos = mylist->m_Size;
	}

	struct LinkNode* pCurrent = &mylist->pHeader;

	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}

	// 此时 pCurrent 就是插入位置的前驱节点

	// 创建新节点
	struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
	newNode->data = data;
	newNode->next = NULL;

	// 建立节点之间的关系
	newNode->next = pCurrent->next;
	pCurrent->next = newNode;

	// 更新链表长度
	mylist->m_Size++;
}

遍历链表

void foreach_LinkList(LinkList list, void(*myPrint)(void*))
{
	if (list == NULL)
	{
		return;
	}

	// 还原真实链表
	struct LList* mylist = list;
	// 创建临时节点
	struct LinkNode* pCurrent = mylist->pHeader.next;
	for (int i = 0; i < mylist->m_Size; i++)
	{
		// 打印输出
		myPrint(pCurrent->data);
		pCurrent = pCurrent->next;
	}
}

按位置删除节点

void remove_LinkList (LinkList list , int pos)
{
	if (list == NULL)
	{
		return;
	}
	// 还原真实链表
	struct LList* mylist = list;

	if (pos < 0 || pos > mylist->m_Size - 1)
	{
		return;
	}

	// 创建临时节点
	struct LinkNode* pCurrent = &mylist->pHeader;

	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}
	
	// 此时pCurrent就是待删除节点的前驱节点

	struct LinkNode* pDel = pCurrent->next;
	// 更改指针指向
	pCurrent->next = pDel->next;
	// 释放待删除节点
	free(pDel);
	pDel = NULL;

	// 更新链表长度
	mylist->m_Size--;
}

按值删除节点

void removeByValue_LinkList(LinkList list, void* data,int(*myCompare)(void*, void*))
{
	if (list == NULL)
	{
		return;
	}

	if (data == NULL)
	{
		return;
	}

	// 还原真实链表
	struct LList* mylist = list;

	// 创建临时节点
	struct LinkNode* pCurrent = &mylist->pHeader;
	struct LinkNode* pDel = pCurrent->next;


	for (int i = 0; i < mylist->m_Size; i++)
	{
		if (myCompare(data,pDel->data))
		{
			// 找到了

			// 更改指针指向
			pCurrent->next = pDel->next;
			// 释放待删除节点
			free(pDel);
			pDel = NULL;

			// 更新链表长度
			mylist->m_Size--;

			break;
		}

		// 没找到,指针向后移动
		pCurrent = pCurrent->next;
		pDel = pCurrent->next;

	}
}

返回链表长度

int size_LinkList(LinkList list)
{
	if (list == NULL)
	{
		return;
	}

	struct LList* mylist = list;

	return mylist->m_Size;
}

清空链表

void clear_LinkList(LinkList list)
{
	if (list == NULL)
	{
		return;
	}

	// 将list还原真实链表结构体
	struct LList* mylist = list;

	struct LinkNode* pCurrent = mylist->pHeader.next;
	struct LinkNode* pNext = NULL;

	for (int i = 0; i < mylist->m_Size; i++)
	{
		pNext = pCurrent->next;

		free(pCurrent);
		pCurrent = pNext;
	}

	mylist->pHeader.next = NULL;

	mylist->m_Size = 0;

}

销毁链表

void destroy_LinkList(LinkList list)
{
	if (list == NULL)
	{
		return;
	}

	// 先清空链表
	clear_LinkList(list);

	// 再销毁链表
	free(list);
	list = NULL;
}

测试

测试结构体类型

struct Person
{
	char name[64];
	int age;
};

回调函数

// 回调函数 打印输出
void printPerson(void* data)
{
	struct Person* p = data;
	printf("name: %s, age: %d\n", p->name, p->age);
}
// 回调函数 对比删除数据
int comparePerson(void* data1, void* data2)
{
	struct Person* p1 = data1;
	struct Person* p2 = data2;

	if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age)
	{
		return 1;
	}

	return 0;
}

测试主程序

void test01()
{
	// 初始化链表
	LinkList mylist = init_LinkList();

	struct Person p1 = { "aaa",18 };
	struct Person p2 = { "bbb",19 };
	struct Person p3 = { "ccc",16 };
	struct Person p4 = { "ddd",13 };
	struct Person p5 = { "eee",14 };
	struct Person p6 = { "fff",20 };

	// 插入数据
	insert_LinkList(mylist, 0, &p1);
	insert_LinkList(mylist, 5, &p2);
	insert_LinkList(mylist, -1, &p3);
	insert_LinkList(mylist, 2, &p4);
	insert_LinkList(mylist, 1, &p5);
	insert_LinkList(mylist, -1 ,&p6);
	
	// 遍历链表 
	// aaa eee bbb ddd ccc fff
	foreach_LinkList(mylist, printPerson);
	printf("链表长度为: %d \n", size_LinkList(mylist));

	// 按位置删除节点
	printf("--------------\n");
	remove_LinkList(mylist, 1);
	foreach_LinkList(mylist,printPerson);
	printf("链表长度为: %d \n", size_LinkList(mylist));

	// 按值删除节点
	printf("--------------\n");
	struct Person pp = { "bbb",19 };
	struct Person p = { "aaa",18 };
	removeByValue_LinkList(mylist, &p, comparePerson);
	removeByValue_LinkList(mylist, &pp, comparePerson);
	foreach_LinkList(mylist, printPerson);
	printf("链表长度为: %d \n", size_LinkList(mylist));

	// 清空链表
	printf("--------------\n");
	clear_LinkList(mylist);
	foreach_LinkList(mylist, printPerson);
	printf("链表长度为: %d \n", size_LinkList(mylist));

	// 销毁链表
	destroy_LinkList(mylist);

}

单向链表-企业版

  • 节点结构体只维护指针区
  • 用户预留4个字节空间, 我们帮助连接数据

链表设计

节点结构体

  • 只维护指针域
struct LinkNode
{
	// 只维护指针域
	struct LinkNode* next;
};

链表结构体

  • 头节点
  • 链表长度
struct LList
{
	// 头节点
	struct LinkNode pHeader;
	// 链表长度
	int m_Size;
};

给到用户的是: void* 取别名 LinkList

typedef void* LinkList;

初始化链表

LinkList init_LinkList()
{
	struct LList* mylist = malloc(sizeof(struct LList));

	if (mylist == NULL)
	{
		return NULL;
	}

	mylist->m_Size = 0;
	mylist->pHeader.next = NULL;

	return mylist;
}

插入节点

// list : 链表地址
// pos : 要插入元素的位置
// data : 要插入数据的地址
void insert_LinkList(LinkList list , int pos, void* data)
{
	if (list == NULL)
	{
		return;
	}
	if (data == NULL)
	{
		return;
	}

	struct LList* mylist = list;

	if (pos < 0 || pos > mylist->m_Size-1)
	{
		pos = mylist->m_Size;
	}

	// 取出用户前四个字节空间
	struct LinkNode* myNode = data;

	// 找到待插入位置的前驱节点
	struct LinkNode* pCurrent = &mylist->pHeader;

	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}

	// 更改指针指向
	myNode->next = pCurrent->next;
	pCurrent->next = myNode;

	// 更新链表长度
	mylist->m_Size++;
}

遍历链表

void foreach_LinkNode(LinkList list, void(*myPrint)(void*))
{
	if (NULL == list)
	{
		return;
	}

	struct LList* mylist = list;

	struct LinkNode* pCurrent = mylist->pHeader.next;

	for (int i = 0; i < mylist->m_Size; i++)
	{
		// pCurrent 就是用户数据的首地址
		myPrint(pCurrent);
		pCurrent = pCurrent->next;
	}
}

按位置删除节点

void removeByPos_LinkList(LinkList list, int pos)
{
	if (list == NULL)
	{
		return;
	}

	struct LList* mylist = list;

	if (pos < 0 || pos > mylist->m_Size - 1)
	{
		return;
	}

	// 找到前驱节点
	struct LinkNode* pCurrent = &mylist->pHeader;

	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}

	// 记录待删节点的位置

	struct LinkNode* pDel = pCurrent->next;

	// 重新建立节点之间的关系
	pCurrent->next = pDel->next;

	//free(pDel);// 数据本身是用户的, 由用户自己管理释放

	// 更新链表长度
	mylist->m_Size--;
}

按值删除节点

void removeByValue_LinkList(LinkList list, void* data, int(*myCompare)(void* , void*))
{
	if (list == NULL)
	{
		return;
	}
	if (data == NULL)
	{
		return;
	}

	struct LList* mylist = list;

	struct LinkNode* pCurrent = &mylist->pHeader;
	struct LinkNode* pDel = pCurrent->next;

	for (int i = 0; i < mylist->m_Size; i++)
	{
		if (myCompare(pDel,data))
		{
			// 找到了
			// 重新建立节点关系
			pCurrent = pDel->next;
			// 更新链表长度
			mylist->m_Size--;
			break;
		}
		pCurrent = pDel;
		pDel = pCurrent->next;
	}
}

清空链表

void clear_LinkList(LinkList list)
{
	if (list == NULL)
	{
		return;
	}

	struct LList* mylist = list;

	struct LinkNode* pCurrent = mylist->pHeader.next;
	struct LinkNode* pNext = pCurrent->next;

	for (int i = 0; i < mylist->m_Size; i++)
	{
		pCurrent = NULL;
		pCurrent = pNext;
		pNext = pNext->next;
	}

	mylist->pHeader.next = NULL;

}

销毁链表

void destroy_LinkList(LinkList list)
{
	if (list == NULL)
	{
		return;
	}

	free(list);
	list = NULL;
}

测试

测试结构体类型

  • 预留前四个字节位置
struct Person
{
	//struct LinkNode node;
	int* a;
	char name[64];
	int age;
};

回调函数

// 回调函数 打印输出
void printPerson(void* data)
{
	struct Person* p = data;
	printf("name: %s, age: %d\n", p->name, p->age);
}
// 回调函数 对比删除数据
int comparePerson(void* data1, void* data2)
{
	struct Person* p1 = data1;
	struct Person* p2 = data2;

	if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age)
	{
		return 1;
	}

	return 0;
}

测试主程序

void test01()
{
	LinkList* mylist = init_LinkList();

	// 创建数据
	struct Person p1 = {NULL, "aaa",18 };
	struct Person p2 = {NULL, "bbb",19 };
	struct Person p3 = {NULL, "ccc",16 };
	struct Person p4 = {NULL, "ddd",13 };
	struct Person p5 = {NULL, "eee",14 };
	struct Person p6 = {NULL, "fff",20 };

	// 插入数据
	insert_LinkList(mylist, 0, &p1);
	insert_LinkList(mylist, -1, &p2);
	insert_LinkList(mylist, 3, &p3);
	insert_LinkList(mylist, 1, &p4);
	insert_LinkList(mylist, 3, &p5);
	insert_LinkList(mylist, 2, &p6);

	// 遍历数据
	// aaa ddd fff bbb eee ccc
	foreach_LinkNode(mylist, printPerson);
	printf("------------------\n");

	// 删除"ddd"节点
	removeByPos_LinkList(mylist, 1);
	foreach_LinkNode(mylist, printPerson);
	printf("------------------\n");

	// 删除"ccc"节点
	struct Person p = { NULL, "ccc",16 };
	removeByValue_LinkList(mylist, &p, comparePerson);
	foreach_LinkNode(mylist, printPerson);
	printf("------------------\n");

	// 清空链表
	clear_LinkList(mylist);

	// 销毁链表
	destroy_LinkList(mylist);
	mylist = NULL;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值