文章目录
前言
提示:以下是本篇文章正文内容,下面案例可供参考
一、动态数组
1.darray.h
#ifndef _DARRAY_H_
#define _DARRAY_H_
// 定义管理动态数组的结构体。
typedef struct darray
{
int cap; // 容量
int size; // 实际元素个数
void **data; // 等价 void *data[]; 数组中存储的都是 地址
}DArray;
// 封装操作 动态数组的 API接口
// 初始化动态数组
DArray *Init_DArray(int cap);
// 插入元素 --- 往哪里插, 插入到哪去, 插什么?
void Insert_DArray(DArray *array, int pos, void *data);
// 删除元素
void Delete_DArray(DArray *array, int pos);
// 遍历 --- 回调函数
void Traverse_DArray(DArray *array, void (*print)(void *));
// 销毁
void Destroy_DArray(DArray *array);
#endif
2.darry.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "darray.h"
// 初始化动态数组
DArray *Init_DArray(int cap)
{
DArray *ptr = (DArray *)malloc(sizeof(DArray));
ptr->cap = cap;
ptr->size = 0;
ptr->data = (void **)malloc(sizeof(void *) * cap);
return ptr;
}
// 插入元素 --- 往哪里插, 插入到哪去, 插什么?
void Insert_DArray(DArray *array, int pos, void *data)
{
// 容错
if (NULL == array || NULL == data)
{
return;
}
if (pos < 0 || pos > array->size)
{
pos = array->size; // 当插入位置,超出尾元素下一位置, 插入到末尾。
}
// 当容量 == size时, 应该自动扩容。
if (array->cap == array->size)
{
// 指定容量扩充为原来的 2 倍。
int newCap = array->cap * 2;
void **space = (void **)malloc(sizeof(void *) * newCap);
// 将 旧数据 拷贝到新内存中
memcpy(space, array->data, sizeof(void *) * array->size);
// 释放旧的内存空间
free(array->data);
array->cap = newCap; // 更新容量
array->data = space;
}
// pos位置之后的元素, 依次后移(前一个元素,覆盖后一个元素)
int i = 0;
for (i = array->size; i > pos; --i)
{
array->data[i] = array->data[i-1];
}
// 将 pos位置插入元素
array->data[pos] = data;
// 更新size
array->size++;
}
// 遍历
void Traverse_DArray(DArray *array, void (*print)(void *))
{
int i = 0;
for (i = 0; i < array->size; i++)
{
// 打印每一个动态数组中的元素。
print(array->data[i]);
}
}
// 删除元素
void Delete_DArray(DArray *array, int pos)
{
}
// 销毁
void Destroy_DArray(DArray *array)
{
}
3.test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "darray.h"
typedef struct Person
{
int id;
char name;
}Person;
void myprint(void *data)
{
Person *p = (Person *)data;
printf("id = %d, name = %c\n", p->id, p->name);
}
int main(void)
{
Person p[10];
// 初始化
DArray *ptr = Init_DArray(5);
// 循环插入到动态数组中
int i= 0;
for (i = 0; i<10; i++)
{
p[i].id = i;
p[i].name = 'A' + i;
// 插入到动态数组
Insert_DArray(ptr, i, &p[i]);
}
// 遍历
Traverse_DArray(ptr, myprint);
return 0;
}
二、单链表
1.linklist
代码如下(示例):
#ifndef _LINKLIST_H_
#define _LINKLIST_H_
// 定义链表结点结构体
typedef struct Node
{
void *data;
struct Node *next;
}Node;
// 定义管理链表的结构体
typedef struct LinkList
{
Node header;
int size;
}LinkList;
// 初始化链表
LinkList* Init_LinkList();
// 插入结点 --- 向哪里插,插到哪,插什么
void Insert_LinkList(LinkList* list, int pos, void* data);
// 删除结点
void Delete_LinkList(LinkList* list, int pos);
// 遍历 -- 回调函数 -- 函数指针 -- 函数地址 -- 函数名
void Traverse_LinkList(LinkList* list, void (*print)(void *));
// 查询 -- 回调函数: compare: 相等返回 1, 不相等返回0
void* Search_LinkList(LinkList* list, void *data, int (*compare)(void *, void *));
/*
//根据数据值, 删除链表结点。
void Del_Data_LinkList(LinkList* list, void* data, int(*compare)(void*, void*))
*/
// 销毁
void Destroy_LinkList(LinkList* list);
#endif //_LINKLIST_H_
2.linklist
代码如下(示例):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"
// 初始化链表
LinkList* Init_LinkList()
{
LinkList* ptr = (LinkList *)malloc(sizeof(LinkList));
if (NULL == ptr)
{
perror("malloc ptr error"); // stderr -- 无缓冲 --- 有数据立即刷。
// printf(); // stdout -- 行缓冲。 遇到\n 会刷新缓冲区。 flush 手动刷新。
return;
}
ptr->header.data = NULL;
ptr->header.next = NULL;
ptr->size = 0;
return ptr;
}
// 插入结点 --- 向哪里插,插到哪,插什么
void Insert_LinkList(LinkList* list, int pos, void* data)
{
// 容错
if (NULL == list || NULL == data)
{
return;
}
if (pos < 0 || pos > list->size)
{
return;
}
// 创建待插入的新结点
Node *pnew = (Node*)malloc(sizeof(Node));
pnew->data = data;
pnew->next = NULL;
// 将 pnew 插入到 pos位置。
// 创建辅助指针, 找寻 pos位置。
Node *pcur = &list->header;
int i = 0;
for (i = 0; i < pos; i++) // 循环结束,pcur指向pos所对应的结点的前一个结点。
{
pcur = pcur->next;
}
pnew->next = pcur->next; // 新结点的下一结点, 是 pos对应的结点(用pcur->next 去表示)
pcur->next = pnew; // pos前一个结点(用pcur)的下一结点,是新结点。
// 更新实际结点个数
list->size++;
}
// 删除结点
void Delete_LinkList(LinkList* list, int pos)
{
if (NULL == list)
{
return ;
}
if (pos < 0 || pos >= list->size)
{
return ;
}
// 定义辅助指针变量 pcur, 找到pos位置。
Node *pcur = &list->header;
int i = 0;
for (i = 0; i < pos; i++)
{
pcur = pcur->next; // 循环结束后, pcur 指向 pos 的前一个结点。
}
// 定义pdel保存pos对应的待删除结点。
Node *pdel = pcur->next;
pcur->next = pdel->next; // 跳过pos对应结点, 让 pcur 的下一个结点为 pos的下一个结点。
free(pdel);
pdel = NULL;
// 更新size
list->size--;
}
// 遍历 -- 回调函数 -- 函数指针 -- 函数地址 -- 函数名
void Traverse_LinkList(LinkList* list, void (*print)(void *))
{
if (NULL == list || NULL == print)
{
return ;
}
// 定义辅助指针 pcur,遍历链表结点。
Node *pcur = list->header.next; // 用第一个数据结点给 pcur 赋初值。
while (pcur)
{
print(pcur->data);
pcur = pcur->next;
}
}
// 查询 -- 回调函数: compare: 相等返回 1, 不相等返回0
void *Search_LinkList(LinkList* list, void *data, int (*compare)(void *, void *))
{
if (NULL == list || NULL == data || compare == NULL)
{
return ;
}
// 定义辅助指针 pcur,遍历链表结点。
Node *pcur = list->header.next; // 用第一个数据结点给 pcur 赋初值。
while (pcur)
{
if (compare(data, pcur->data))
{
break; // 找到 与data对应的 数据结点。 该结点保存在pcur中。
}
pcur = pcur->next;
}
// 遍历所有链表结点,没有找到与data一致的数据, 循环结束。pcur === NULL
if (NULL == pcur)
{
return NULL;
}
return pcur->data;
} /*
void Del_Data_LinkList(LinkList* list, void* data, int(*compare)(void*, void*))
{
if (NULL == list || NULL == data || compare == NULL)
{
return ;
}
int pos=1;
// 定义辅助指针 pcur,遍历链表结点。
Node *pcur = list->header.next; // 用第一个数据结点给 pcur 赋初值。
while (pcur)
{
if (compare(data, pcur->data))
{
break; // 找到 与data对应的 数据结点。 该结点保存在pcur中。
}
pcur = pcur->next;
pos++;
}
// 遍历所有链表结点,没有找到与data一致的数据, 循环结束。pcur === NULL
if (NULL == pcur)
{
return 0;
}
return pos;
}*/
// 销毁
void Destroy_LinkList(LinkList* list)
{
if (NULL == list)
{
return ;
}
// 定义辅助指针 pcur, 遍历链表结点
Node *pcur = list->header.next;
while (pcur)
{
Node *pdel = pcur; // 保存当前待释放结点的地址。
pcur = pcur->next;
free(pdel);
}
free(list);
list = NULL;
}
3.
void Del_Data_LinkList(LinkList* list, void* data, int(*compare)(void*, void*));
int Search_Pos(LinkList* list, void* data, int(*compare)(void*, void*));
// 参照 Seach_LinkList() 修改,根据 data 获取 pos
int Search_Pos(LinkList* list, void* data, int(*compare)(void*, void*))
{
if (list == NULL || data == NULL || compare == NULL)
{
return -1;
}
int pos = 0;
// 用链表中的每一个节点, 和data比较
Node* pcur = list->header.next;
while (pcur)
{
// 比较两个变量是否相等
if (compare(pcur->data, data))
{
break;
}
pcur = pcur->next;
pos++;
}
// pcur 指向的地址中的数据和data指向的地址中的数据相等
if (pcur == NULL)
{
return -1;
}
return pos;
}
void Del_Data_LinkList(LinkList* list, void* data, int(*compare)(void*, void*))
{
// 先找到 data 在 list中的 pos 位置。—— 参照 Seach_LinkList() 修改, 获取 pos
int pos = Search_Pos(list, data, compare);
// 按位置删除。
Delete_LinkList(list, pos);
}
// 调用测试
Del_Data_LinkList(list, &p[3], compare);
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
Traverse_LinkList(list, myprint);
4.
void Reverse_LinkList(LinkList* list, void(*print)(void*));
void Recursion(Node* node, void(*print)(void*));
// 链表逆序遍历
void Reverse_LinkList(LinkList* list, void(*print)(void*))
{
if (list == NULL || print == NULL)
{
return;
}
// 启动递归,遍历链表
Recursion(list->header.next, print);
}
void Recursion(Node* node, void(*print)(void*))
{
// 递归结束条件,尾结点
if (node == NULL)
{
return;
}
// 开始递归调用自己
Recursion(node->next, print);
// 出栈的时候(链表遍历完成 node == NULL)执行的操作
print(node->data);
}
// 调用测试
printf("|||||||||||||||||||||||||||||||||||||||||\n");
Reverse_LinkList(list, myprint);
5.test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "linklist.h"
// 初始化链表
LinkList* Init_LinkList()
{
LinkList* ptr = (LinkList *)malloc(sizeof(LinkList));
if (NULL == ptr)
{
perror("malloc ptr error"); // stderr -- 无缓冲 --- 有数据立即刷。
// printf(); // stdout -- 行缓冲。 遇到\n 会刷新缓冲区。 flush 手动刷新。
return;
}
ptr->header.data = NULL;
ptr->header.next = NULL;
ptr->size = 0;
return ptr;
}
// 插入结点 --- 向哪里插,插到哪,插什么
void Insert_LinkList(LinkList* list, int pos, void* data)
{
// 容错
if (NULL == list || NULL == data)
{
return;
}
if (pos < 0 || pos > list->size)
{
return;
}
// 创建待插入的新结点
Node *pnew = (Node*)malloc(sizeof(Node));
pnew->data = data;
pnew->next = NULL;
// 将 pnew 插入到 pos位置。
// 创建辅助指针, 找寻 pos位置。
Node *pcur = &list->header;
int i = 0;
for (i = 0; i < pos; i++) // 循环结束,pcur指向pos所对应的结点的前一个结点。
{
pcur = pcur->next;
}
pnew->next = pcur->next; // 新结点的下一结点, 是 pos对应的结点(用pcur->next 去表示)
pcur->next = pnew; // pos前一个结点(用pcur)的下一结点,是新结点。
// 更新实际结点个数
list->size++;
}
// 删除结点
void Delete_LinkList(LinkList* list, int pos)
{
if (NULL == list)
{
return ;
}
if (pos < 0 || pos >= list->size)
{
return ;
}
// 定义辅助指针变量 pcur, 找到pos位置。
Node *pcur = &list->header;
int i = 0;
for (i = 0; i < pos; i++)
{
pcur = pcur->next; // 循环结束后, pcur 指向 pos 的前一个结点。
}
// 定义pdel保存pos对应的待删除结点。
Node *pdel = pcur->next;
pcur->next = pdel->next; // 跳过pos对应结点, 让 pcur 的下一个结点为 pos的下一个结点。
free(pdel);
pdel = NULL;
// 更新size
list->size--;
}
// 遍历 -- 回调函数 -- 函数指针 -- 函数地址 -- 函数名
void Traverse_LinkList(LinkList* list, void (*print)(void *))
{
if (NULL == list || NULL == print)
{
return ;
}
// 定义辅助指针 pcur,遍历链表结点。
Node *pcur = list->header.next; // 用第一个数据结点给 pcur 赋初值。
while (pcur)
{
print(pcur->data);
pcur = pcur->next;
}
}
// 查询 -- 回调函数: compare: 相等返回 1, 不相等返回0
void *Search_LinkList(LinkList* list, void *data, int (*compare)(void *, void *))
{
if (NULL == list || NULL == data || compare == NULL)
{
return ;
}
// 定义辅助指针 pcur,遍历链表结点。
Node *pcur = list->header.next; // 用第一个数据结点给 pcur 赋初值。
while (pcur)
{
if (compare(data, pcur->data))
{
break; // 找到 与data对应的 数据结点。 该结点保存在pcur中。
}
pcur = pcur->next;
}
// 遍历所有链表结点,没有找到与data一致的数据, 循环结束。pcur === NULL
if (NULL == pcur)
{
return NULL;
}
return pcur->data;
} /*
void Del_Data_LinkList(LinkList* list, void* data, int(*compare)(void*, void*))
{
if (NULL == list || NULL == data || compare == NULL)
{
return ;
}
int pos=1;
// 定义辅助指针 pcur,遍历链表结点。
Node *pcur = list->header.next; // 用第一个数据结点给 pcur 赋初值。
while (pcur)
{
if (compare(data, pcur->data))
{
break; // 找到 与data对应的 数据结点。 该结点保存在pcur中。
}
pcur = pcur->next;
pos++;
}
// 遍历所有链表结点,没有找到与data一致的数据, 循环结束。pcur === NULL
if (NULL == pcur)
{
return 0;
}
return pos;
}*/
// 销毁
void Destroy_LinkList(LinkList* list)
{
if (NULL == list)
{
return ;
}
// 定义辅助指针 pcur, 遍历链表结点
Node *pcur = list->header.next;
while (pcur)
{
Node *pdel = pcur; // 保存当前待释放结点的地址。
pcur = pcur->next;
free(pdel);
}
free(list);
list = NULL;
}
三、栈
1.顺序栈
1.seqstack.h
#ifndef _SEQSTACK_H_
#define _SEQSTACK_H_
#define MAXSIZE 50
// 创建管理栈的结构体
typedef struct seqstack
{
void *data[MAXSIZE]; // 静态数组,存储栈数据
int top; // 记录数组尾元素(栈顶元素)下标
}SeqStack;
// 初始化空栈
void InitStack(SeqStack *st);
// 清空栈
void ClearStack(SeqStack *st);
// 获取栈顶元素
void *GetTop(SeqStack *st);
// 入栈(压栈)
void PushStack(SeqStack *st, void *data);
// 出栈(弹栈)
void PopStack(SeqStack *st);
// 获取栈元素数 -- 栈大小
int SizeStack(SeqStack *st);
#endif
2.seqstack
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqstack.h"
// 初始化空栈
void InitStack(SeqStack *st)
{
if (st == NULL)
return;
st->top = -1; // 不能指定为 >=0 的有效下标。 、
memset(st->data, 0, sizeof(st->data));
}
// 清空栈
void ClearStack(SeqStack *st)
{
InitStack(st); // 将栈恢复成初始化状态
}
// 获取栈顶元素
void *GetTop(SeqStack *st)
{
if (NULL == st || st->top == -1) // 当 top 为 -1,栈为空。
{
return ;
}
return st->data[st->top];
}
// 入栈(压栈)
void PushStack(SeqStack *st, void *data)
{
if (NULL == st || data == NULL)
{
return ;
}
if (st->top == MAXSIZE-1)
{
return ;
}
st->top++;
st->data[st->top] = data;
}
// 出栈(弹栈)
void PopStack(SeqStack *st)
{
if (NULL == st)
{
return ;
}
if (st->top == -1)
{
return ;
}
st->top--;
}
// 获取栈元素数 -- 栈大小
int SizeStack(SeqStack *st)
{
if (NULL == st)
{
return ;
}
return st->top + 1;
}
3.test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "seqstack.h"
typedef struct Person
{
int id;
char name;
}Person;
int main(void)
{
Person p[10];
// 初始化栈
SeqStack st;
InitStack(&st);
// 循环将数据插入到栈中
int i = 0;
for (i = 0; i < sizeof(p)/sizeof(p[0]); i++)
{
p[i].id = i;
p[i].name = i+'a';
PushStack(&st, &p[i]);
}
printf("1st --stack size = %d\n", SizeStack(&st));
// 借助循环 + 获取栈顶元素 + 弹栈 模拟遍历。
while (SizeStack(&st))
{
// 获取栈顶元素
Person *pret = (Person *)GetTop(&st);
printf("id = %d, name=%c\n", pret->id, pret->name);
PopStack(&st);
}
printf("2nd --stack size = %d\n", SizeStack(&st));
// 清空
ClearStack(&st);
return 0;
}
2.链栈
1.LinkStack.h
#ifndef _LINKSTACK_H_
#define _LINKSTACK_H_
// 链表结点结构体
typedef struct Node
{
struct Node* next; // 没有数据域
}Node;
// 管理 链式栈 机构体
typedef struct LinkStack
{
int size;
Node* top;
}LinkStack;
// 初始化空链式栈
void InitStack(LinkStack *st);
// 清空栈
void ClearStack(LinkStack* st);
// 获取栈顶元素
void* GetTop(LinkStack* st);
// 压栈(入栈)—— 对应的,要将 node 添加为 Person 首个成员。
void PushStack(LinkStack* st, Node *node);
// 弹栈(出栈)
void PopStack(LinkStack* st);
// 栈大小
int SizeStack(LinkStack* st);
#endif // _LINKSTACK_H_
2.LinkStack.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "LinkStack.h"
// 初始化空链式栈
void InitStack(LinkStack* st)
{
if (NULL == st)
return;
st->size = 0;
st->top = NULL; // 永远指向第一个数据结点。 NULL 表没有指向。
}
// 清空栈
void ClearStack(LinkStack* st)
{
// InitStack(st); 【方法1】
// 【方法2】:有可能,需要释放链表的结点。
if (NULL == st)
return;
while (st->size)
{
PopStack(st); // 利用Pop, 如果需要删除、释放, 都在 Pop中。
}
}
// 获取栈顶元素
void* GetTop(LinkStack* st)
{
if (0 == st->size)
return NULL;
return st->top; // 返回第一个数据结点。
}
// 压栈(入栈)—— 对应的,要将 node 添加为 Person 首个成员。
void PushStack(LinkStack* st, Node* node)
{
if (NULL == st || NULL == node)
return;
// 采用 头插法
node->next = st->top; // 新结点node,将变为 头。原来的 top 是其下一个结点。
st->top = node; // 让 top 指向新结点。
st->size++;
}
// 弹栈(出栈)
void PopStack(LinkStack* st)
{
// 没数据, 不用执行弹栈了。
if (NULL == st || st->size == 0)
return;
st->top = st->top->next; // top指向当前结点的下一个结点
st->size--;
}
// 栈大小
int SizeStack(LinkStack* st)
{
if (NULL == st)
return 0;
return st->size;
}
3.test
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "LinkStack.h"
// 初始化空链式栈
void InitStack(LinkStack* st)
{
if (NULL == st)
return;
st->size = 0;
st->top = NULL; // 永远指向第一个数据结点。 NULL 表没有指向。
}
// 清空栈
void ClearStack(LinkStack* st)
{
// InitStack(st); 【方法1】
// 【方法2】:有可能,需要释放链表的结点。
if (NULL == st)
return;
while (st->size)
{
PopStack(st); // 利用Pop, 如果需要删除、释放, 都在 Pop中。
}
}
// 获取栈顶元素
void* GetTop(LinkStack* st)
{
if (0 == st->size)
return NULL;
return st->top; // 返回第一个数据结点。
}
// 压栈(入栈)—— 对应的,要将 node 添加为 Person 首个成员。
void PushStack(LinkStack* st, Node* node)
{
if (NULL == st || NULL == node)
return;
// 采用 头插法
node->next = st->top; // 新结点node,将变为 头。原来的 top 是其下一个结点。
st->top = node; // 让 top 指向新结点。
st->size++;
}
// 弹栈(出栈)
void PopStack(LinkStack* st)
{
// 没数据, 不用执行弹栈了。
if (NULL == st || st->size == 0)
return;
st->top = st->top->next; // top指向当前结点的下一个结点
st->size--;
}
// 栈大小
int SizeStack(LinkStack* st)
{
if (NULL == st)
return 0;
return st->size;
}
四.二叉树
#include <stdio.h>
// 定义二叉树的结点结构体
typedef struct BinaryTree
{
char data;
struct BinaryTree *left;
struct BinaryTree *right;
}BinTree;
// 先序遍历 --- 递归
void PreOrder(BinTree *root)
{
// 递归终止条件
if (NULL == root)
return ;
printf("%c ", root->data);
PreOrder(root->left);
PreOrder(root->right);
}
// 中序遍历 --- 递归
void MidOrder(BinTree *root)
{
// 递归终止条件
if (NULL == root)
return ;
MidOrder(root->left);
printf("%c ", root->data);
MidOrder(root->right);
}
int main(void)
{
BinTree a, b, c, d, e, f, g;
memset(&a, 0, sizeof(BinTree));
memset(&b, 0, sizeof(BinTree));
memset(&c, 0, sizeof(BinTree));
memset(&d, 0, sizeof(BinTree));
memset(&e, 0, sizeof(BinTree));
memset(&f, 0, sizeof(BinTree));
memset(&g, 0, sizeof(BinTree));
a.data = 'A';
a.left = &b;
a.right = &c;
b.data = 'B';
b.left = &d;
b.right = &e;
c.data = 'C';
c.left = &f;
c.right = &g;
d.data = 'D';
e.data = 'E';
f.data = 'F';
g.data = 'G';
// 先序
PreOrder(&a);
printf("\n----------------\n");
MidOrder(&a);
return 0;
}