3. 线性表
3.2. 链表
3.2.2. 单向链表
有头单向链表的函数操作
5. 链表指定位置删除数据
int deletePostLinkList(link_node_t *p, int post) { // 容错判断 if (post < 0 || post >= lengthLinkList(p) || p->next == NULL) { perror("Delete location error"); return -1; } // 头指针移动到post的前一个节点的地址 for (int i = 0; i < post; i++) p = p->next; // 定义pdel ,指向被删除节点 link_list_t pdel = p->next; // 头指针指针域跨过被删除节点 p->next = pdel->next; // 释放被删除节点的地址,pdel置空 free(pdel); pdel = NULL; return 0; }
6. 判断链表是否为空
int isEmptyLinkList(link_node_t *p) { return p->next == NULL; }
7. 清空单向链表
// 头节点不动,每次删除头节点后面的节点,让头节点的指针域跨过被删除节点 void clearLinkList(link_node_t *p) { // 定义pdel link_list_t pdel = NULL; // 循环删除 while (p->next != NULL) { // 指向被删除节点,头节点的下一个节点 pdel = p->next; // 头节点的指针域跨过被删除节点 p->next = pdel->next; // 释放被删除节点 free(pdel); pdel = NULL; } }
8. 修改指定位置的数据
int changePostLinkList(link_node_t *p, int post, datatype data) { // 容错判断 if (post < 0 || post >= lengthLinkList(p)) { perror("post err!!"); } else if (isEmptyLinkList(p)) { printf("The linked list is empty!!\n"); } // 头指针指向被修改的节点 for (int i = 0; i <= post; i++) { p = p->next; } // 修改数据 p->data = data; return 0; }
9. 查找指定数据出现的位置
int searchDataLinkList(link_node_t *p, datatype data) { // 定义一个变量,存放查找到的下标 int post = 0; // 遍历链表 while (p != NULL) { p = p->next; // 节点的数据域与data比较 if (p->data == data) { // 相等结束返回下标 return post; } // 不相等,变量++ post++; } // 遍历结束没找到,返回-1 return -1; }
10. 删除单向链表中出现的指定数据
int deleteDataLinkList(link_node_t *p, datatype data) { // 定义一个pdel, 用来指向被删除节点 link_list_t pdel = p->next; //计算一共删了多少个 int i = 0; // 指针q 遍历链表 while (pdel != NULL) { if (pdel->data == data) { p->next = pdel->next; // 跨过被删除节点 free(pdel); // 删除节点 pdel = p->next; i++; } else { p = p->next; pdel = pdel->next; } } return i; }
11. 转置链表
void reverseLinkList(link_node_t *p) { // 定义 ptail,最后指向最后一个节点 link_list_t ptail = p->next; // 定义指针temp,指向尾指针的下一个节点 link_list_t t = ptail->next; while (ptail->next != NULL) { t = ptail->next; ptail->next = t->next; t->next = p->next; p->next = t; } }
3.2.3. 单向循环链表
约瑟夫环问题,是一个经典的循环链表问题,题意是:已知 n 个人(分别用编号 1,2,3,…,n 表示)围坐在一张圆桌周围,从编号为 k 的人开始顺时针报数,数到 m 的那个人出列;他的下一个人又从 1 开始,还是顺时针开始报数,数到 m 的那个人又出列;依次重复下去,直到圆桌上剩余一个人。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct node_t
{
int data;
struct node_t *next;
}link_node_t,*link_list_t;
int main(int argc, const char *argv[])
{
int i;
link_list_t pdel = NULL; //用于指向被删除节点
link_list_t ptail = NULL; //永远指向当前链表的尾
link_list_t pnew = NULL; //永远指向新创建的节点
link_list_t h = NULL;
int all_num = 7; //猴子总数
int start_num = 2; //从几号猴子开始数
int kill_num = 3; //数到几杀死猴
// printf("请您输入猴子总数 起始号码 数到几杀死:\n");
// scanf("%d%d%d",&all_num,&start_num,&kill_num);
//1.创建出一个单向循环链表
//(1)创建有all_num个节点的单向链表
h = (link_list_t)malloc(sizeof(link_node_t));
if(NULL == h)
{
perror("malloc failed");
return -1;
}
h->data = 1;
h->next = NULL;
ptail = h; //尾指针指向当前的第一个节点
for(i = 2; i <= all_num; i++)
{
//创建新的节点
pnew = (link_list_t)malloc(sizeof(link_node_t));
if(NULL == pnew)
{
perror("malloc failed");
return -1;
}
//将新节点装上数据
pnew->data = i;
pnew->next = NULL;
//将新节点链接到链表尾
ptail->next = pnew; //链接到链表的尾
ptail = pnew; //尾指针继续指向当前链表的尾
}
//(2)将头指针保存到链表的尾形成单向循环链表
ptail->next = h; //形成单向循环链表
//2.开始杀猴子
//(1)将头指针移动到开始猴子的号码处
for(i = 1; i < start_num; i++)
h = h->next;
printf("start :%d\n",h->data);
//(2)循环进行杀猴子
while(h != h->next)//终止:就剩一个猴子,只有一个节点
{
//将头指针移动到即将删除节点的前一个节点
for(i = 1; i < kill_num-1; i++)
h = h->next;
pdel = h->next;
//跨过删除节点
h->next = pdel->next;
printf("kill is -------------%d\n",pdel->data);
free(pdel);
pdel = NULL;
//杀死猴子猴后,从下一个节点开始继续开始数,将头指针移动到开始数的地方
h = h->next;
}
printf("king is=================== %d\n",h->data);
return 0;
}
4. 栈—stack
4.1. 什么是栈
1. 入栈和出栈只能在一端完成,另一端是封闭的
2. 遵循先入后出 FILO,后入先出 LIFO
3. 完成入栈出栈操作的一段成为栈顶,另一端称为栈底
4. 栈是只能在一端插入和删除的线性表,又称堆栈
4.2. 顺序栈
4.2.1. 特性
逻辑结构:线性结构
存储结构:顺序存储
操作:创建,入栈,出栈,清空,判空,判满
4.2.2. 代码实现
头文件:seqstack.h
#ifndef __SEQSTACK_H__ #define __SEQSTACK_H__ typedef int datatype; typedef struct seqstack { datatype *data; //指向栈的存储位置 int maxlen; //保存栈的最大长度 int top; //称为栈针,用的时候可以当作顺序表里的last来使用 //top始终代表当前栈内最后一个有效元素的下标 } seqstack_t; //1.创建一个空栈,len代表创建栈时的最大长度。 seqstack_t *createEmptySeqStack(int len); //2.判断是否为满,满返回1 未满返回0 int isFullSeqStack(seqstack_t *p); //3.入栈,data代表入栈的数据 int pushStack(seqstack_t *p, int data); //4.判断栈是否为空 int isEmptySeqStack(seqstack_t *p); //5.出栈,返回出栈数据 int popSeqStack(seqstack_t *p); //6. 清空栈 void clearSeqStack(seqstack_t *p); //7. 获取栈顶数据(注意不是出栈操作,如果出栈,相当于删除了栈顶数据,只是将栈顶的数据获取到,不需要移动栈针) int getTopSeqStack(seqstack_t *p); //8. 求栈的长度,返回长度。 int lengthSeqStack(seqstack_t *p); #endif
1. 创建一个空栈
// 1.创建一个空栈,len代表创建栈时的最大长度。 seqstack_t *createEmptySeqStack(int len) { // 申请空间存放栈的结构 seqstack_t *p = (seqstack_t *)malloc(sizeof(seqstack_t)); if (p == NULL) { printf("Space opening failure!!\n"); return -1; } // 初始化 p->maxlen = len; p->top = -1; p->data = (datatype *)malloc(sizeof(datatype) * len); if (p->data == NULL) { printf("initialization failed!!\n"); return -1; } return p; }
2. 判断是否为满
int isFullSeqStack(seqstack_t *p) { return p->top+1 == p->maxlen; }
3. 入栈
int pushStack(seqstack_t *p, int data) { // 容错判断 if (isFullSeqStack(p)) { printf("Space is full!!\n"); return -1; } // 入栈操作 p->data[++p->top] = data; return 0; }
4. 判断是否为空
int isEmptySeqStack(seqstack_t *p) { return p->top == -1; }
5. 出栈
int popSeqStack(seqstack_t *p) { // 容错判断 if (isEmptySeqStack(p)) { printf("Space is empty!!\n"); } return p->data[p->top--]; }
6. 清空栈
void clearSeqStack(seqstack_t *p) { p->top = -1; }
7. 获取最顶上的数据,不是出栈
int getTopSeqsStack(seqstack_t *p) { // 容错判断 if (isEmpSeqStack(p)) { printf("Space is empty!!\n"); } return p->data[p->top]; }
8. 求栈的长度,返回长度
int lengthSeqStack(seqstack *p) { reutrn p->top+1; }