01 昨天课程回顾
02 循环链表思路
(这个图画的不好,实际下面实现的是企业级链表next都在最上面)
如何判断是否循环过一遍了
第一种方式:判断next是不是等于头结点
第二种方式:通过size判断
代码中的片段: (通过第一种方式)
03 循环链表框架
04 循环链表框架实现
05 循环链表测试
CircleLinkList.h:
#ifndef CIRCLELINKLIST
#define CIRCLELINKLIST
#include <stdio.h>
#include <stdlib.h>
// 单向循环链表
// 链表的小结点 里面的内容就是一个指针
typedef struct CIRCLELINKNODE {
struct CIRCLELINKNODE * next;
} CircleLinkNode;
// 链表结构体
typedef struct CIRCLELINKLIST {
// 如果用指针的话需要单独malloc指针指向结构体的内容大小,所以这里直接用对象了
CircleLinkNode head;
int size;
} CircleLinkList;
// 编写针对链表结构体操作的API函数
#define CIRCLELINKLIST_TRUE 1
#define CIRCLELINKLIST_FALSE 0
// 比较回调
typedef int(*COMPARENODE)(CircleLinkNode *,CircleLinkNode *);
// 打印回调
typedef void(*PRINTNODE) (CircleLinkNode*);
// 初始化函数
CircleLinkList * Init_CircleLinkList();
// 插入函数
void Insert_CircleLinkList(CircleLinkList * clist,int pos,CircleLinkNode * data);
// 获得第一个元素
CircleLinkNode * Front_CircleLinkList(CircleLinkList *clist);
// 根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList * clist,int pos);
// 根据值去删除
void RemoveByValue_CircleLinkList(CircleLinkList * clist, CircleLinkNode *data, COMPARENODE conpare);
// 获得链表的长度
int Size_CircleLinkList(CircleLinkList * clist);
// 判断是否为空
int IsEmpty_CircleLinkList(CircleLinkList * clist);
// 查找
int Find_CircleLinkList(CircleLinkList * clist,CircleLinkNode *data,COMPARENODE compare);
// 打印节点
void Print_CircleLinkList(CircleLinkList * clist,PRINTNODE print);
// 释放内存
void FreeSpace_CircleLinkList(CircleLinkList * clist);
#endif
CircleLinkList.c:
#include "CircleLinkList.h"
// 初始化函数
CircleLinkList * Init_CircleLinkList() {
// 在堆空间分配CircleLinkList大小的内存 用CircleLinkList*指针指向它
CircleLinkList* clist = (CircleLinkList *)malloc(sizeof(CircleLinkList));
// linklist结构体的头指向linklist结构体的小结点本身
clist->head.next = &(clist->head);
// 初始化size 为0
clist->size = 0;
return clist;
};
// 插入函数
void Insert_CircleLinkList(CircleLinkList * clist, int pos, CircleLinkNode * data)
{
if (clist == NULL) {
return;
}
if (data == NULL) {
return;
}
if (pos < 0 || pos > clist->size) {
pos = clist->size;
}
// 根据位置查找结点
// 辅助指针变量 是头结点的地址
CircleLinkNode * pCurrent = &(clist->head);
for (int i = 0; i < pos;i++) {
pCurrent = pCurrent->next;
}
// 新数据入链表
// 1.先找到pCurrent,然后让data的next指向pCurrent的next
data->next = pCurrent->next;
// 2.让pCurrent的next指向data
pCurrent->next = data;
clist->size++;
};
// 获得第一个元素
CircleLinkNode * Front_CircleLinkList(CircleLinkList *clist)
{
return clist->head.next;
};
// 根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList * clist, int pos)
{
if (clist == NULL) {
return;
}
if (pos <0 || pos >= clist->size) {
return;
}
// 根据pos找结点
// 辅助指针变量
// 辅助指针变量指向 第一个结点
CircleLinkNode * pCurrent = &(clist->head);
for (int i = 0; i < pos;i++) {
pCurrent = pCurrent->next;
}
// 缓存当前结点的下一个结点
CircleLinkNode* pNext = pCurrent->next;
// 让当前结点的下一个结点指向 之前缓存结点的下一个结点
pCurrent->next = pNext->next;
clist->size--;
};
// 根据值去删除
void RemoveByValue_CircleLinkList(CircleLinkList * clist, CircleLinkNode *data, COMPARENODE compare)
{
if (clist == NULL) {
return;
}
if (data == NULL) {
return;
}
// 这个是循环链表
// 指向头结点
CircleLinkNode* pPrev = &(clist->head);
// 指向第一个结点
CircleLinkNode * pCurrent = pPrev->next;
int i = 0;
for (i = 0; i < clist->size; i++) {
if (compare(pCurrent,data) ==CIRCLELINKLIST_TRUE ) {
// 删除
pPrev->next = pCurrent->next;
break;
}
// 向下走
pPrev = pCurrent;
pCurrent = pPrev->next;
}
clist->size--;
};
// 获得链表的长度
int Size_CircleLinkList(CircleLinkList * clist)
{
return clist->size;
};
// 判断是否为空
int IsEmpty_CircleLinkList(CircleLinkList * clist)
{
if (clist->size == 0) {
// 1
return CIRCLELINKLIST_TRUE;
}
// 0
return CIRCLELINKLIST_FALSE;
};
// 查找
int Find_CircleLinkList(CircleLinkList * clist, CircleLinkNode *data, COMPARENODE compare)
{
if (clist == NULL) {
return -1;
}
if (data == NULL) {
return -1;
}
// 指向第一个结点
CircleLinkNode * pCurrent = clist->head.next;
int flag = -1;
for (int i = 0; i < clist->size;i++) {
if (compare(pCurrent,data) == CIRCLELINKLIST_TRUE) {
flag = i;
break;
}
pCurrent = pCurrent->next;
}
return flag;
};
// 打印节点
void Print_CircleLinkList(CircleLinkList * clist, PRINTNODE print)
{
if (clist == NULL) {
return;
}
// 辅助指针变量
// 指向第一个结点
CircleLinkNode * pCurrent = clist->head.next;
// 循环三次
for (int i = 0; i < clist->size * 3;i++) {
// 如果pCurrent等于clist的head(即小结点的地址)
// 那么说明已经从第一个结点开始循环遍历过一遍了
if (pCurrent == &(clist->head)) {
// 如果循环到了头结点,那么再指向第一个结点
pCurrent = pCurrent->next;
printf("---------- ");
}
print(pCurrent);
pCurrent = pCurrent->next;
}
};
// 释放内存
void FreeSpace_CircleLinkList(CircleLinkList * clist)
{
if (clist == NULL) {
return;
}
free(clist);
};
Source.c:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CircleLinkList.h"
// 定义PERSON结构体 (企业级链表)
typedef struct PERSON {
CircleLinkNode node;
char name[64];
int age;
int score;
}Person;
// 打印
void MyPrint(CircleLinkNode *data) {
Person * p = (Person *)data;
printf("Name:%s Age:%d Score:%d ", p->name,p->age,p->score);
}
// 对比
int MyCompare(CircleLinkNode * data1, CircleLinkNode * data2) {
Person * p1 = (Person *)data1;
Person * p2 = (Person *)data2;
// 如果三个都相等就返回true // C语言中没有boolean类型
if (strcmp(p1->name, p2->name) == 0 && p1->age == p2->age && p1->score == p2->score)
{
return CIRCLELINKLIST_TRUE;
}
return CIRCLELINKLIST_FALSE;
}
int main(void) {
// 创建循环链表
CircleLinkList* clist = Init_CircleLinkList();
// 创建数据
Person p1, p2, p3, p4, p5;
strcpy(p1.name, "aaa");
strcpy(p2.name, "bbb");
strcpy(p3.name, "ccc");
strcpy(p4.name, "ddd");
strcpy(p5.name, "eee");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
p1.score = 55;
p2.score = 50;
p3.score = 60;
p4.score = 65;
p5.score = 70;
// 数据入链表
// 需要进行类型转换
Insert_CircleLinkList(clist, 100, (CircleLinkNode *)&p1);
Insert_CircleLinkList(clist, 100, (CircleLinkNode *)&p2);
Insert_CircleLinkList(clist, 100, (CircleLinkNode *)&p3);
Insert_CircleLinkList(clist, 100, (CircleLinkNode *)&p4);
Insert_CircleLinkList(clist, 100, (CircleLinkNode *)&p5);
// 打印
Print_CircleLinkList(clist, MyPrint);
Person pDel;
strcpy(pDel.name, "ddd");
pDel.age = 40;
pDel.score = 65;
// 根据值删除
RemoveByValue_CircleLinkList(clist, (CircleLinkNode *)&pDel, MyCompare);
printf(" ");
Print_CircleLinkList(clist, MyPrint);
// 释放内存
FreeSpace_CircleLinkList(clist);
system("pause");
return 0;
}
06 约瑟夫问题
07 栈的顺序存储框架搭建
08 栈的顺序存储框架实现
09 栈的顺序存储测试
数组模拟栈的顺序存储:
入栈时候把data放到data[stack->size]中 size++
出栈时候删除stack->data[stack->size-1] size—
seqstack.h:
#ifndef SEQSTACK_H
#define SEQSTACK_H
#include <stdlib.h>
#include <stdio.h>
// 数组去模拟栈的顺序存储
#define MAX_SIZE 2014
#define SEQSTACK_TRUE 1
#define SEQSTACK_FALSE 0
// 顺序栈 结构体
typedef struct SEQSTACK {
// 数组里面放void * 类型数据
void * data[MAX_SIZE];
// size记录大小
int size;
} SeqStack;
// 初始化 栈
SeqStack* Init_SeqStack();
// 入栈
void Push_SeqStack(SeqStack * stack, void *data);
// 返回栈顶元素
void * Top_SeqStack(SeqStack *stack);
// 出栈
void Pop_SeqStack(SeqStack * stack);
// 判断是否 为空
int isEmpty(SeqStack * stack);
// 返回栈中元素的个数
int Size_SeqStack(SeqStack *stack);
// 清空栈
void Clear_SeqStack(SeqStack *stack);
// 销毁
void FreeSpace_SeqStack(SeqStack *stack);
#endif
seqstack.c:
#include "SeqStack.h"
// 初始化 栈
SeqStack* Init_SeqStack()
{
SeqStack * stack = (SeqStack*)malloc(sizeof(SeqStack));
// 栈中data数组(类型为void *)的值为NULL
for (int i = 0; i < MAX_SIZE; i++) {
stack->data[i] = NULL;
}
// 栈的size为0
stack->size = 0;
return stack;
}
// 入栈
void Push_SeqStack(SeqStack * stack, void *data)
{
if (stack == NULL) {
return;
}
// 如果达到了最大的栈的长度,就不能再入栈了 这里MAX_SIZE是2014
if (stack->size == MAX_SIZE) {
return;
}
if (data == NULL)
{
return;
}
// 把data放到 data[stack->size] 中
stack->data[stack->size] = data;
// stack的长度增加
stack->size++;
}
// 返回栈顶元素
void * Top_SeqStack(SeqStack *stack)
{
if (stack == NULL) {
return NULL;
}
if (stack->size == 0) {
return NULL;
}
// 返回stack->data[stack->size-1]
return stack->data[stack->size - 1];
}
// 出栈
void Pop_SeqStack(SeqStack * stack)
{
if (stack == NULL) {
return;
}
if (stack->size == 0) {
return;
}
// 删除stack->data[stack->size-1]的值
stack->data[stack->size - 1] = NULL;
stack->size--;
}
// 判断是否 为空
int isEmpty(SeqStack * stack)
{
if (stack == NULL)
{
return -1;
}
if (stack->size == 0) {
return SEQSTACK_TRUE;
}
return SEQSTACK_FALSE;
}
// 返回栈中元素的个数
int Size_SeqStack(SeqStack *stack)
{
return stack->size;
}
// 清空栈
void Clear_SeqStack(SeqStack *stack)
{
if (stack == NULL) {
return;
}
for (int i = 0; i < stack->size; i++) {
stack->data[i] = NULL;
}
stack->size = 0;
}
// 销毁
void FreeSpace_SeqStack(SeqStack *stack)
{
if (stack != NULL) {
return;
}
free(stack);
}
source.c:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SeqStack.h"
// 定义结构体—人
typedef struct PERSON {
char name[64];
int age;
} Person;
int main(void) {
// 创建栈
SeqStack * stack = Init_SeqStack();
// 创建数据
Person p1 = { "aaa",10 };
Person p2 = { "bbb",20 };
Person p3 = { "ccc",30 };
Person p4 = { "ddd",40 };
Person p5 = { "eee",50 };
// 入栈
Push_SeqStack(stack, &p1); // 这个入栈操作是让stack结构体中数组的void *指针指向p1的地址 p1是在堆上的
Push_SeqStack(stack, &p2);
Push_SeqStack(stack, &p3);
Push_SeqStack(stack, &p4);
Push_SeqStack(stack, &p5);
// 输出
while (Size_SeqStack(stack) > 0) {
// 访问栈顶元素
Person* person = (Person *)Top_SeqStack(stack);
printf("Name:%s Age:%d ", person->name, person->age);
// 弹出栈顶元素
Pop_SeqStack(stack);
}
// 释放内存
FreeSpace_SeqStack(stack);
printf(" ");
system("pause");
return 0;
}
10 栈的链式存储框架搭建
11 栈的链式存储框架实现
12 栈的链式存储测试
入栈操作:
linkstack.h:
#ifndef LINKSTACK_H
#define LINKSTACK_H
#include <stdlib.h>
#include <stdio.h>
// 链式栈的结点
typedef struct LINKNODE {
// 这个小结点内部就是一个指向自身类型的next指针
struct LINKNODE *next;
}LinkNode;
// 链式栈 结构体
typedef struct LINKSTACK {
// head指向小结点
LinkNode head;
// size
int size;
} LinkStack;
// 初始化函数
LinkStack* Init_LinkStack();
// 入栈
void Push_LinkStack(LinkStack * stack,LinkNode * data);
// 出栈
void Pop_LinkStack(LinkStack * stack);
// 返回栈顶元素
LinkNode * Top_LinkStack(LinkStack * stack);
// 返回栈元素的个数
int Size_LinkStack(LinkStack * stack);
// 清空栈
void Clear_LinkStack(LinkStack * stack);
// 销毁栈
void FreeSpace_LinkStack(LinkStack * stack);
#endif
linkStack.c:
#include "LinkStack.h"
// 初始化函数
LinkStack* Init_LinkStack() {
// 在堆空间上初始化LinkStack大小
LinkStack * stack = (LinkStack *)malloc(sizeof(LinkStack));
// 第一个结点设置为NULL
stack->head.next = NULL;
// 初始化size为0
stack->size = 0;
return stack;
}
// 入栈
void Push_LinkStack(LinkStack * stack, LinkNode * data)
{
if (stack == NULL) {
return;
}
if (data == NULL) {
return;
}
// 入栈操作 让新的data指向 stack结构体头结点指向的内容
data->next = stack->head.next;
// 让stack头结点指向新data
stack->head.next = data;
/*
之后每次有新的入栈
都会让data指向 stack结构体头结点已经指向的内容(即:上一个data的位置)
然后让stack结构体的头结点指向这个新data
*/
// size增长
stack->size++;
}
// 出栈
void Pop_LinkStack(LinkStack * stack)
{
if (stack == NULL) {
return NULL;
}
if (stack->size == 0) {
return;
}
// 取到stack结构体头结点指向的结点 (即栈顶结点)
LinkNode * pNext = stack->head.next;
// stack结构体头结点 指向栈顶结点的下一个结点
stack->head.next = pNext->next;
stack->size--;
}
// 返回栈顶元素
LinkNode * Top_LinkStack(LinkStack * stack)
{
if (stack == NULL) {
return NULL;
}
if (stack->size == 0) {
return NULL;
}
// 返回的是第一个结点
return stack->head.next;
}
// 返回栈元素的个数
int Size_LinkStack(LinkStack * stack)
{
if (stack == NULL) {
return -1;
}
// 返回stack->size
return stack->size;
}
// 清空栈
void Clear_LinkStack(LinkStack * stack)
{
if (stack == NULL) {
return;
}
// 第一个节点设为NULL
stack->head.next = NULL;
// size设置为0
stack->size = 0;
}
// 销毁栈
void FreeSpace_LinkStack(LinkStack * stack)
{
if (stack == NULL) {
return;
}
free(stack);
}
Source.c:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkStack.h"
// 定义 结构体 人
typedef struct PERSON {
// 企业链表
LinkNode node;
char name[64];
int age;
}Person;
int main(void) {
// 创建栈
LinkStack * stack = Init_LinkStack();
// 创建数据
Person p1, p2, p3, p4, p5;
strcpy(p1.name, "aaa");
strcpy(p2.name, "bbb");
strcpy(p3.name, "ccc");
strcpy(p4.name, "ddd");
strcpy(p5.name, "eee");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
// 入栈
Push_LinkStack(stack, (LinkNode *)&p1);
Push_LinkStack(stack, (LinkNode *)&p2);
Push_LinkStack(stack, (LinkNode *)&p3);
Push_LinkStack(stack, (LinkNode *)&p4);
Push_LinkStack(stack, (LinkNode *)&p5);
// 输出
while (Size_LinkStack(stack) > 0) {
// 取出栈顶元素
Person * p = (Person *)Top_LinkStack(stack);
printf("Name:%s Age:%d ",p->name,p->age);
// 弹出栈顶元素
Pop_LinkStack(stack);
}
// 销毁栈
FreeSpace_LinkStack(stack);
system("pause");
return 0;
}
13 队列的顺序存储框架搭建
哪一端当队头都可以 ,因为哪一端操作都要移动元素
14 队列的顺序存储框架实现
15 队列的顺序存储测试
seqqueue.h:
#ifndef SEQQUEUE_H
#define SEQQUEUE_H
#define MAX_SIZE 1024
#include <stdlib.h>
#include <stdio.h>
// 顺序队列结构体
typedef struct SEQQUEUE{
// 数组 数组存放void*类型指针
void* data[MAX_SIZE];
// 顺序队列结构体大小
int size;
} SeqQueue;
// 初始化
SeqQueue* Init_SeqQueue();
// 入队
void Push_SeqQueue(SeqQueue * queue, void * data);
// 返回队头元素
void * Front_SeqQueue(SeqQueue * queue);
// 出队
void Pop_SeqQueue(SeqQueue * queue);
// 返回队尾元素
void * Back_SeqQueue(SeqQueue* queue);
// 返回大小
int Size_SeqQueue(SeqQueue * queue);
// 清空队列
void Clear_SeqQueue(SeqQueue * queue);
// 销毁
void FreeSpace_SeqQueue(SeqQueue * queue);
#endif
seqqueue.c:
#include "SeqQueue.h"
// 初始化
SeqQueue* Init_SeqQueue()
{
// 在堆空间分配SeqQueue大小的结构体
SeqQueue * queue = (SeqQueue *)malloc(sizeof(SeqQueue));
for (int i = 0;i<MAX_SIZE;i++)
{
// 初始化队列所有的data都为NULL
queue->data[i] = NULL;
// 初始化size为0
queue->size = 0;
}
// 返回队列
return queue;
};
// 入队
void Push_SeqQueue(SeqQueue * queue, void * data)
{
// 数组左边当作队头
if (queue == NULL) {
return;
}
if(data == NULL) {
return;
}
// 如果达到了最大数组长度 就返回
if (queue->size == MAX_SIZE) {
return;
}
// 把data赋值给给数组的最后一个空间
queue->data[queue->size] = data;
// size++
queue->size++;
};
// 返回队头元素
void * Front_SeqQueue(SeqQueue * queue)
{
if (queue == NULL) {
return NULL;
}
if (queue->size == 0) {
return NULL;
}
// 因为把数组左边当头了,队列先进先出 如果返回队头元素
// 就是把第0个元素返回
// 把数组第0个元素返回
return queue->data[0];
};
// 出队
void Pop_SeqQueue(SeqQueue * queue)
{
// 需要移动元素
if (queue == NULL) {
return;
}
if (queue->size == 0) {
return;
}
// 从第0个位置开始把所有数据向左移动
for (int i = 0; i < queue->size - 1;i++) {
queue->data[i] = queue->data[i + 1];
}
// size--
queue->size--;
};
// 返回队尾元素
void * Back_SeqQueue(SeqQueue* queue)
{
if (queue == NULL) {
return NULL;
}
if (queue->size == 0) {
return NULL;
}
return queue->data[queue->size-1];
};
// 返回大小
int Size_SeqQueue(SeqQueue * queue)
{
if (queue == NULL) {
return -1;
}
return queue->size;
};
// 清空队列
void Clear_SeqQueue(SeqQueue * queue)
{
if (queue == NULL) {
return;
}
for (int i = 0; i < queue->size; i++)
{
queue->data[i] = NULL;
}
queue->size = 0;
};
// 销毁
void FreeSpace_SeqQueue(SeqQueue * queue)
{
if (queue == NULL) {
return;
}
free(queue);
};
source.c:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SeqQueue.h"
typedef struct PERSON {
char name[64];
int age;
} Person;
int main(void)
{
// 创建队列
SeqQueue * queue = Init_SeqQueue();
// 创建数据
Person p1 = { "aaa",10 };
Person p2 = { "bbb",20 };
Person p3 = { "ccc",30 };
Person p4 = { "ddd",40 };
Person p5 = { "eee",50 };
// 数据入队列
Push_SeqQueue(queue, &p1);
Push_SeqQueue(queue, &p2);
Push_SeqQueue(queue, &p3);
Push_SeqQueue(queue, &p4);
Push_SeqQueue(queue, &p5);
// 输出
while (Size_SeqQueue(queue) > 1) {
// 取出队头元素
Person *p = (Person *)Front_SeqQueue(queue);
printf("Name:%s Age:%d ", p->name, p->age);
// 从队头弹出元素
Pop_SeqQueue(queue);
}
// 输出队尾元素
Person* backPerson = (Person *)Back_SeqQueue(queue);
printf("Name:%s Age:%d ",backPerson->name,backPerson->age);
// 销毁队列
FreeSpace_SeqQueue(queue);
printf(" ");
system("pause");
return 0;
}