一、线性表的顺序存储结构
1、头文件
// 防止头文件重复包含
#ifndef DYNAMIC_ARRAY_H
#define DYNAMIC_ARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//线性表的顺序存储:用一块连续的存储空间
//动态增长内存,将真正存放数据的内存放到堆上
//动态数据 5个元素,空间不足,申请内存,拷贝数据,释放旧存储 capacity
//实现先申请capacity空间的容量,不够了再申请
typedef struct DYNAMICARRAY{
int* paddr; //存放数据的地址
int size; //当前有多少个元素
int capacity; //容器的容量
} DynamicArray;
//撰写一系列对此结构体进行操作的函数
//初始化(创建操作)
DynamicArray* initArray();
//插入操作
void push_back(DynamicArray* arr, int value);
//删除操作(根据位置删除)
void removeByPos(DynamicArray* arr, int pos);
//根据值删除(值第一次出现的位置)
void removeByValue(DynamicArray* arr, int value);
//释放动态数组的内存
void freeSpace(DynamicArray* arr);
//查找
int findByValue(DynamicArray* arr, int value);
//打印数组
void printArray(DynamicArray* arr);
//清空数组
void clearArray(DynamicArray* arr);
//capacity 这块内存空间一共可以存放多少元素
int capacityArray(DynamicArray* arr);
//size 记录当前数组中具体的元素个数
int sizeArray(DynamicArray* arr);
//根据位置获取每个位置信息
int atIndex(DynamicArray* arr, int pos);
#endif
2、实现部分
#include "DynamicArray.h"
//撰写一系列对此结构体进行操作的函数
//初始化(创建操作)
DynamicArray* initArray() {
//申请内存
DynamicArray* myArray = (DynamicArray*)malloc(sizeof(DynamicArray));
//初始化
myArray->size = 0;
myArray->capacity = 20;
myArray->paddr = (int*)malloc(sizeof(int) * myArray->capacity);
return myArray;
}
//插入操作
void push_back(DynamicArray* arr, int value) {
if (arr == NULL) {
return;
}
//判断空间是否足够
if (arr->size == arr->capacity) {
//进行空间的扩展,新空间是旧空间的两倍
int* newSpace = (int*)malloc(sizeof(int) * arr->capacity * 2);
//拷贝数据到新的空间
memcpy(newSpace, arr->paddr, arr->capacity*sizeof(int));
//释放旧空间内存
free(arr->paddr);
//更新容量
arr->capacity = arr->capacity * 2;
arr->paddr = newSpace;
}
//插入新元素
arr->paddr[arr->size] = value;
arr->size++;
}
//删除操作(根据位置删除)
void removeByPos(DynamicArray* arr, int pos) {
if (arr == NULL) {
return;
}
//判断位置是否有效
if (pos < 0 || pos >= arr->size) {
return;
}
//删除元素
for (int i = pos; i < arr->size-1; i++) {
arr->paddr[i] = arr->paddr[i + 1];
}
arr->size--;
}
//根据值删除(值第一次出现的位置)
void removeByValue(DynamicArray* arr, int value) {
if (arr == NULL) {
return;
}
//找到值的位置
int pos = findByValue(arr, value);
if (pos != -1) {
removeByPos(arr, pos);
}
}
//释放动态数组的内存
void freeSpace(DynamicArray* arr) {
if (arr == NULL) {
return;
}
if (arr->paddr != NULL) {
free(arr->paddr);
}
free(arr);
}
//查找
int findByValue(DynamicArray* arr, int value) {
if (arr == NULL) {
return -1;
}
//找到值得位置
int pos = -1;
for (int i = 0; i < arr->size; i++) {
if (arr->paddr[i] == value) {
pos = i;
break;
}
}
return pos;
}
//打印数组
void printArray(DynamicArray* arr) {
if (arr == NULL) {
return;
}
for (int i = 0; i < arr->size; i++) {
printf("%d ", arr->paddr[i]);
}
printf("\n");
}
//清空数组
void clearArray(DynamicArray* arr) {
if (arr == NULL) {
return;
}
//空间值赋0,代表清空数组
arr->size = 0;
}
//capacity 这块内存空间一共可以存放多少元素
int capacityArray(DynamicArray* arr) {
if (arr == NULL) {
return -1;
}
return arr->capacity;
}
//size 记录当前数组中具体的元素个数
int sizeArray(DynamicArray* arr) {
if (arr == NULL) {
return -1;
}
return arr->size;
}
//根据位置获取每个位置信息
int atIndex(DynamicArray* arr, int pos) {
if (arr == NULL) {
return -1;
}
return arr->paddr[pos];
}
3、测试
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DynamicArray.h"
void test01() {
//初始化动态数组
DynamicArray* myArray = initArray();
printf("数组容量: %d\n", capacityArray(myArray));
printf("数组元素个数:%d\n", sizeArray(myArray));
//插入元素
for (int i = 0; i < 100; i++) {
push_back(myArray, i);
}
//打印
printArray(myArray);
printf("数组容量: %d\n", capacityArray(myArray));
printf("数组元素个数:%d\n", sizeArray(myArray));
//销毁
freeSpace(myArray);
}
int main(void) {
test01();
system("pause");
return 0;
}
二、线性表的链式存储
1、头文件
#ifndef SINGLELIST_H
#define SINGLELIST_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//线性表的链式存储
//链表节点
typedef struct LINKNODE {
void* data; //无类型指针可以指向任何类型数据
struct LINKNODE* next;
}LinkNode;
//链表结构体
typedef struct LINKLIST {
LinkNode* head; //头结点
int size; //链表是按需创建空间,所以不需要实现分配容量
}LinkList;
//打印函数指针
typedef void(*PRINTLINKNODE)(void*);
//初始化链表
LinkList* initLinkList();
//指定位置插入
void insertLinkList(LinkList* list, int pos, void* data);
//删除指定位置的值
void removeByPos(LinkList* list, int pos);
//获取链表的长度
int size(LinkList* list);
//返回第一个节点的数据
void* getFront(LinkList* list);
//释放链表内存
void freeSpaceLinkList(LinkList* list);
//查找某个值
int findByPos(LinkList* list, void* data);
//打印链表节点
void printLinkList(LinkList* list, PRINTLINKNODE print);
#endif
2、实现部分
#include "SingleList.h"
//初始化链表
LinkList* initLinkList() {
//初始化就是对链表结构体进行操作
LinkList* list = (LinkList*)malloc(sizeof(LinkList));
list->size = 0;
//头节点不保存数据信息,只是为了链表实现起来思路清晰
list->head = (LinkNode*)malloc(sizeof(LinkNode));
list->head->data = NULL;
list->head->next = NULL;
return list;
}
//指定位置插入
void insertLinkList(LinkList* list, int pos, void* data){
if (list == NULL) {
return;
}
if (data == NULL) {
return;
}
//友好的处理,pos越界,插入尾部
if (pos < 0 || pos >= list->size) {
pos = list->size;
}
//插入节点
//1、创建新的节点
LinkNode* newnode = (LinkNode*)malloc(sizeof(LinkNode));
newnode->data = data;
newnode->next = NULL;
//2、插入新节点
//先找到待插入位置节点的前驱
LinkNode* pCurrent = list->head;
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//3、新节点入链表
newnode->next = pCurrent->next;
pCurrent->next = newnode;
list->size++;
}
//删除指定位置的值
void removeByPos(LinkList* list, int pos) {
if (list == NULL) {
return;
}
if (pos < 0 || pos >= list->size) {
return;
}
//查找删除节点的前驱
//这里是因为存在一个无数据节点head,所以这种方式可以遍历找到前驱
LinkNode* pCurrent = list->head;
for (int i = 0; i < pos; i++) {
pCurrent = pCurrent->next;
}
//缓存待删除节点
LinkNode* pDel = pCurrent->next;
pCurrent->next = pDel->next;
//释放删除节点的内存
free(pDel);
list->size--;
}
//获取链表的长度
int size(LinkList* list){
return list->size;
}
//返回第一个节点的数据
void* getFront(LinkList* list){
return list->head->next->data;
}
//释放链表内存
void freeSpaceLinkList(LinkList* list){
if (list == NULL) {
return;
}
//辅助指针
LinkNode* pCurrent = list->head;
while (pCurrent != NULL) {
//先缓存下一个节点,再删除当前节点
LinkNode* pNext = pCurrent->next;
free(pCurrent); //释放当前节点
pCurrent = pNext;
}
//释放链表内存
list->size = 0;
free(list);
}
//查找某个值
int findByPos(LinkList* list, void* data){
if (list == NULL) {
return -1;
}
if (data == NULL) {
return -1;
}
//遍历查找
LinkNode* pCurrent = list->head->next;
int i = 0;
while (pCurrent != NULL) {
if (pCurrent->data == data) {
break;
}
i++;
pCurrent = pCurrent->next;
}
return i; //返回位置
}
//打印链表节点
void printLinkList(LinkList* list, PRINTLINKNODE print){
if (list == NULL) {
return;
}
//定义辅助指针变量
LinkNode* pCurrent = list->head->next;
while (pCurrent != NULL) {
print(pCurrent->data);
pCurrent = pCurrent->next;
}
}
3、测试
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SingleList.h"
//测试数据
typedef struct PERSON {
char name[64];
int age;
int score;
}Person;
//打印函数
void MyPrint(void* data) {
Person* p = (Person*)data;
printf("Name: %s, age: %d, score: %d\n", p->name, p->age, p->score);
}
int main(void) {
//创建链表
LinkList* list = initLinkList();
//创建数据
Person p1 = { "aaa", 18, 100 };
Person p2 = { "bbb", 28, 90 };
Person p3 = { "ccc", 38, 80 };
Person p4 = { "ddd", 48, 110 };
//数据插入链表
insertLinkList(list, 0, &p1);
insertLinkList(list, 0, &p2);
insertLinkList(list, 0, &p3);
insertLinkList(list, 0, &p4);
//打印
printf("======================\n");
printLinkList(list, MyPrint);
//链表第一个节点
printf("头结点数据为:\n");
Person* ret = (Person*)getFront(list);
printf("Name: %s, age: %d, score: %d\n", ret->name, ret->age, ret->score);
//销毁列表
freeSpaceLinkList(list);
return 0;
}