C语言核心知识点Day08

1.线性表

1.1基本概念
	线性表是零个或者多个数据元素的有限序列,数据元素之间是有顺序的,数据元素
个数是有限的,数据元素的类型必须相同。

1.2线性表的顺序存储
	顺序表是线性表的一种,也就是说,将线性表中的元素一个接一个的存储在一块连
续的存储区域中,这种顺序表示的线性表也成为顺序表。对于线性表来讲,对于线性
表的首结点,只有后继元素没有前驱元素;对于尾结点,只有前驱结点没有后继结点,
其余的结点,既有前驱结点,也有后继结点。

1.3 顺序表的优点和缺点
优点:
	无需为线性表中的逻辑关系增加额外的空间。
	可以快速的获取表中合法位置的元素。
	
缺点:
	插入和删除操作需要移动大量元素。
	
1.4 线性表的顺序存储代码实现
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>



struct DynamicArr
{
	//表示的是指向数组的指针
	void** pArr;
	//表示容量
	int m_capacity;
	//大小
	int m_size;
};

//遍历动态数组回调函数
void func(void* a)
{
	int* tempInt = a;
	printf("%d\n", *tempInt);
}

//删除指定元素(按照值删除)回调函数
int deleteValue(void* a1, void* a2)
{
	int* a = a1;
	int* b = a2;
	if (*a == *b)
		return 1;
	else
		return 0;
}

// 初始化创建数组
struct DynamicArr* initDyArr(int capacity);

//动态数组插入元素
void insertDyArr(struct DynamicArr* arr, void* arrElent, int size);

//遍历动态数组
void showDyArr(struct DynamicArr* arr, void(*pFunc)(void*));

//删除指定元素(按照位置删除)
void deleposDyArr(struct DynamicArr* arr, int index);

//删除指定元素(按照值删除)
void delevalueDyArr(struct DynamicArr* arr, void* value, int(*valueP)(void*, void*));

//销毁整个数组
void destroyDyArr(struct DynamicArr* arr);


//测试
void test01()
{
	struct DynamicArr* arr = initDyArr(5);
	printf("容量:%d\n", arr->m_capacity);
	printf("大小:%d\n", arr->m_size);

	int a = 6;
	int b = 5;
	int c = 4;
	int d = 3;
	int e = 2;
	int f = 1;

	insertDyArr(arr, &a, 0);
	insertDyArr(arr, &b, 0);
	insertDyArr(arr, &c, 2);
	insertDyArr(arr, &d, 3);
	insertDyArr(arr, &e, 4);
	insertDyArr(arr, &f, 0);

	printf("容量:%d\n", arr->m_capacity);
	printf("大小:%d\n", arr->m_size);
	//func(arr->pArr[1]);

	showDyArr(arr, func);

	//deleposDyArr(arr,1);
	int temp = 1;
	delevalueDyArr(arr, &temp, deleteValue);
	printf("删除后:\n");
	printf("容量:%d\n", arr->m_capacity);
	printf("大小:%d\n", arr->m_size);
	showDyArr(arr, func);
	printf("销毁后:\n");
	destroyDyArr(arr);
	showDyArr(arr, func);

}

int main()
{
	test01();
	return 0;
}

//初始化创建数组
struct DynamicArr* initDyArr(int capacity)
{
	if (capacity <= 0)
		return NULL;
	//在堆区创建数组
	struct DynamicArr* arr = (struct DynamicArr*)malloc(sizeof(struct DynamicArr));
	if (arr == NULL)
		return NULL;

	arr->pArr = (void**)malloc(sizeof(void*) * capacity);
	arr->m_capacity = capacity;
	arr->m_size = 0;

	return arr;
}

//动态数组插入元素
void insertDyArr(struct DynamicArr* arr, void* arrElent, int size)
{
	//判断输入有效性
	if (arr == NULL || size < 0)
		return;

	//超出上限开辟新数组
	int tempSize = arr->m_size;
	if (size > arr->m_capacity || arr->m_size == arr->m_capacity)
	{
		//更新新创建数组的容量
		int newCapacity = arr->m_capacity * 2;
		//创建新空间
		void** newPrr = malloc(sizeof(void*) * newCapacity);
		//内容拷贝
		for (int i = 0; i < arr->m_capacity; i++)
		{
			newPrr[i] = arr->pArr[i];

		}

		free(arr->pArr);
		//重新让新数组指向arr
		arr->pArr = newPrr;
		arr->m_capacity = newCapacity;
	}

	if (size >= arr->m_size)
	{
		//默认尾插法
		arr->pArr[arr->m_size] = arrElent;
		arr->m_size++;
		return;
	}

	//按位置插入
	tempSize = arr->m_size;//5

	while (1)
	{
		if (arr->m_size == size)
		{
			//找到指定位置后插入,更新数组大小
			arr->pArr[size] = arrElent;
			arr->m_size = tempSize + 1;
			break;
		}
		//数组移位
		arr->pArr[arr->m_size] = arr->pArr[arr->m_size - 1];//p[5] = p[4],p[4] = p[3],p[3] = p[2],p[2] = p[1],p[1] = p[0];
		arr->m_size--; //0
	}
	return;
}

//遍历动态数组
void func(void* a)
{
	int* tempInt = a;
	printf("%d\n", *tempInt);
}

void showDyArr(struct DynamicArr* arr, void(*pFunc)(void*))
{
	//判断输入有效性
	if (arr == NULL)
		return;
	//遍历
	for (int i = 0; i < arr->m_size; ++i)
	{
		pFunc(arr->pArr[i]);
	}
}

//删除指定元素(按照位置删除)
void deleposDyArr(struct DynamicArr* arr, int index)
{
	//判断输入有效性
	if (arr == NULL)
		return;
	//遍历
	for (int i = index - 1; i < arr->m_size - 1; ++i)
	{
		arr->pArr[i] = arr->pArr[i + 1];
	}
	arr->m_size--;
}

//删除指定元素(按照值删除)
int deleteValue(void* a1, void* a2)
{
	int* a = a1;
	int* b = a2;
	if (*a == *b)
		return 1;
	else
		return 0;
}

//删除指定元素(按值删除)
void delevalueDyArr(struct DynamicArr* arr, void* value, int(*valueP)(void*, void*))
{
	//判断输入有效性
	if (arr == NULL)
		return;
	//遍历
	for (int i = 0; i < arr->m_size; ++i)
	{
		if (valueP(arr->pArr[i], value))
		{
			for (int j = i; j < arr->m_size; j++)
			{
				arr->pArr[j] = arr->pArr[j + 1];
			}
			break;
		}

	}
	arr->m_size--;
}

//销毁整个数组
void destroyDyArr(struct DynamicArr* arr)
{
	if (arr == NULL)
		return;

	if (arr->pArr != NULL)
	{
		free(arr->pArr);
		arr->pArr = NULL;
	}

	free(arr);
	arr = NULL;
}

2.1线性表的链式存储(单向链表)
	前面我们写的线性表的顺序存储(动态数组)的案例,最大的缺点是插入和删除时
需要移动大量元素,这可以通过链表来解决。
	链表为了表示每个数据元素与其直接后继元素之间的逻辑关系,每个元素除了
存储本身的信息外,还需要存储指示其直接后继的信息。

2.2单链表
	线性表的链式存储结构中,每个节点中只包含一个指针域,这样的链表叫单链表。
通过每个节点的指针域将线性表的数据元素按其逻辑次序链接在一起。
	
2.3优点和缺点
优点:
	无需一次性定制链表的容量 
	插入和删除操作无需移动数据元素
缺点:
	数据元素必须保存后继元素的位置信息
	获取指定数据的元素操作需要顺序访问之前的元素
	
2.4线性表的链式存储(单链表实现)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//自定义数据类型
struct Person
{
	char name[64];
	int age;
};

//定义链表
struct LinkList
{
	void* m_data;//数据域
	struct LinkList* next;//指针域
	int m_linkNum;
};

//初始化链表
struct LinkList* init_Linklist()
{
	struct LinkList* list = malloc(sizeof(struct LinkList));
	if (list == NULL)
		return NULL;

	list->next = NULL;
	list->m_linkNum = 0;

	return list;
}

//插入链表(按位置插入)
void insert_Linklist(struct LinkList* list,void* value,int pos)
{
	if (list == NULL)
		return;
	if (value == NULL)
		return;
	//默认尾插法
	if (pos < 0 || pos > list->m_linkNum)
		pos = list->m_linkNum;

	struct LinkList* temp1_insert = list;
	
	for (int i = 0; i < pos; i++)
	{
		temp1_insert = temp1_insert->next;
	}

	struct LinkList* temp2_insert = malloc(sizeof(struct LinkList));
	//初始化新结点
	temp2_insert->m_data = value;
	temp2_insert->next = NULL;
	//新结点加入到指定位置
	temp2_insert->next = temp1_insert->next;
	temp1_insert->next = temp2_insert;

	list->m_linkNum++;

}

//遍历链表
void printStruct(void* temp)
{
	struct Person* p1 = temp;
	printf("姓名:%s,年龄:%d\n", p1->name, p1->age);
}

void find_Linklist(struct LinkList* list,void(*pPrint)(void*))
{
	if (list == NULL)
		return;

	struct LinkList* temp = list;
	printf("链表中元素个数为:%d\n", list->m_linkNum);
	for (int i = 0; i < list->m_linkNum; i++)
	{
		temp = temp->next;
		pPrint(temp->m_data);
	}
}

//删除链表中的元素(坐标)
void delete_indexLinklist(struct LinkList* list, int pos)
{
	if (list == NULL || pos < 0 || pos > list->m_linkNum)
		return;

	struct LinkList* temp_del = list;

	//被删元素的前驱结点
	for (int i = 0; i < pos; i++)
	{
		temp_del = temp_del->next;
	}

	struct LinkList* temp2_del = malloc(sizeof(struct LinkList));
	//找出被删除的元素,使用指针去维护被删除的空间
	temp2_del = temp_del->next;
	//更新被删元素前驱结点的指向
	temp_del->next = temp2_del->next;

	//释放被删结点
	free(temp2_del);
	//更新内容
	list->m_linkNum--;
}

//删除链表中的元素(值)
//回调函数
int myCompare(void* temp1,void* temp2)
{
	struct Person* p1 = temp1;
	struct Person* p2 = temp2;

	return p1->age == p2->age && p1->name == p2->name;
}

void delete_valueLinklist(struct LinkList* list, void* value,int(*pCompare)(void*,void*))
{
	if (list == NULL || value == NULL)
		return;

	struct LinkList* temp_del = list;

	//被删元素的前驱结点
	for (int i = 0; i < list->m_linkNum; i++)
	{
		temp_del = temp_del->next;
		if (pCompare(temp_del->next->m_data, value))
		{
			break;
		}	
	}

	struct LinkList* temp2_del = malloc(sizeof(struct LinkList));
	//找出被删除的元素,使用指针去维护被删除的空间
	temp2_del = temp_del->next;
	//更新被删元素前驱结点的指向
	temp_del->next = temp2_del->next;

	//释放被删结点
	free(temp2_del);
	//更新内容
	list->m_linkNum--;
}

//清空
void clear_Linklist(struct LinkList* list)
{
	if (list == NULL)
		return;

	struct LinkList* temp1 = list->next;
	//struct LinkList* temp2 = temp1->next;

	for (int i = 0; i < list->m_linkNum; i++)
	{
		struct LinkList* temp2 = temp1->next;
		free(temp1);
		temp1 = temp2;
	}

	list->next = NULL;
	list->m_linkNum = 0;
}

//销毁链表
void destroy_Linklist(struct LinkList* list)
{
	if (list == NULL)
		return;

	clear_Linklist(list);

	free(list);
	list = NULL;
}

void test()
{
	//初始化链表
	struct LinkList* m_List = init_Linklist();

	struct Person p1 = { "张三",22 };
	struct Person p2 = { "李四",23 };
	struct Person p3 = { "王五",18 };
	struct Person p4 = { "麻子",20 };
	struct Person p5 = { "伙夫",19 };
	//插入数据
	insert_Linklist(m_List, &p1, 0);
	insert_Linklist(m_List, &p2, 0);
	insert_Linklist(m_List, &p3, 0);
	insert_Linklist(m_List, &p4, 0);
	insert_Linklist(m_List, &p5, 0);

	//遍历
	printf("插入后链表内容为:\n");
	find_Linklist(m_List, printStruct);

	//删除
	printf("删除后链表内容为:\n");
	//按坐标删除
	//delete_indexLinklist(m_List, 2);
	//按元素删除
	delete_valueLinklist(m_List, &p1, myCompare);
	find_Linklist(m_List, printStruct);

	//清空
	clear_Linklist(m_List);
	printf("清空后链表内容为:\n");
	find_Linklist(m_List, printStruct);

	//销毁
	destroy_Linklist(m_List);
}

int main()
{
	test();
	return 0;
}
下面附带另外一种写法:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//结点
struct LinkNode
{
	struct LinkNode* next;
};
//链表
struct LinkList
{
	struct LinkNode n_head;
	int n_size;
};

//自定义数据类型
struct Person
{
	struct LinkNode node;
	char name[64];
	int age;
};

//初始化链表
struct LinkList* init_Linklist()
{
	struct LinkList* mylist = malloc(sizeof(struct LinkList));
	if (mylist == NULL)
		return NULL;

	mylist->n_head.next = NULL;
	mylist->n_size = 0;

	return mylist;
}

//插入
void insert_Linklist(struct LinkList* list,void* value,int pos)
{
	if (list == NULL || value == NULL)
		return;

	//位置不正确时默认使用尾插法
	if (pos < 0 || pos > list->n_size - 1 )
		pos = list->n_size;

	struct LinkList* m_list = list;

	//找到插入位置的前驱结点
	struct LinkNode* mValue = value;
	struct LinkNode* pCurrent = &m_list->n_head;

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

//遍历
void myPrint(void* temp)
{
	struct Person* p = temp;
	printf("姓名:%s,年龄:%d\n", p->name, p->age);
}

void find_Linklist(struct LinkList* list,void(*pPrint)(void*))
{
	if (list == NULL)
		return;

	struct LinkList* m_list = list;
	struct LinkNode* pCurrent = &m_list->n_head.next;

	for (int i = 0; i < m_list->n_size; i++) 
	{
		myPrint(pCurrent->next);
		pCurrent = pCurrent->next;
	}
}
//删除链表中元素
void delete_Linklist(struct LinkList* list, int pos)
{
	if (list == NULL)
		return;

	if (pos<0 || pos > list->n_size)
		return;

	struct LinkList* m_list = list;
	struct LinkNode* pCurrent = &m_list->n_head.next;

	for (int i = 0; i < pos; i++)
	{
		pCurrent = pCurrent->next;
	}
	struct LinkNode* pTemp = pCurrent->next;
	pCurrent->next = pTemp->next;
	
	m_list->n_size--;
}

//清空
void clear_Linklist(struct LinkList* list)
{
	if (list == NULL)
		return;

	struct LinkList* m_list = list;
	struct LinkNode* pCurrent = &m_list->n_head.next;

	for (int i = 0; i < m_list->n_size; i++)
	{
		struct LinkList* m_Temp = pCurrent->next;
		free(pCurrent);
		pCurrent = m_Temp;
	}

	m_list->n_head.next = NULL;
	m_list->n_size = 0;

}

//销毁
void dextroy_Linklist(struct LinkList* list)
{
	if (list == NULL)
		return;

	clear_Linklist(list);
	free(list);

	list = NULL;
}

void test()
{
	//初始化链表
	struct LinkList* m_List = init_Linklist();

	struct Person p1 = { NULL,"张三",22 };
	struct Person p2 = { NULL,"李四",23 };
	struct Person p3 = { NULL,"王五",18 };
	struct Person p4 = { NULL,"麻子",20 };
	struct Person p5 = { NULL,"伙夫",19 };

	//插入数据
	insert_Linklist(m_List, &p1, 3);
	insert_Linklist(m_List, &p2, 0);
	insert_Linklist(m_List, &p3, 0);
	insert_Linklist(m_List, &p4, 0);
	insert_Linklist(m_List, &p5, 0);

	//遍历
	printf("插入后链表内容为:\n");
	find_Linklist(m_List, myPrint);

	//删除
	printf("删除后链表内容为:\n");

	delete_Linklist(m_List, 2);
	find_Linklist(m_List, myPrint);

	//清空
	printf("清空后链表内容为:\n");
	clear_Linklist(m_List);
	find_Linklist(m_List, myPrint);

	销毁
	dextroy_Linklist(m_List);

}

int main()
{
	test();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值