O( )表示法 时间复杂度 空间复杂度
#include<stdlib.h>
#include<stdio.h>
#include<string>
//算法最终编译成具体的计算机指令
//每一个指令,在具体的计算机上运行速度固定
//通过具体的n的步骤,就可以推导出算法的复杂度
long sum1(int n) //2n+4 ===>O(n) 空间复杂度 O(n)
{
long ret = 0; //1 4
int* array = (int*)malloc(n * sizeof(int));//1 4n
int i = 0;//1 4
for (i = 0; i < n; i++) //n
{
array[i] = i + 1;
}
for (i = 0; i < n; i++) //n
{
ret += array[i];
}
free(array); //1
return ret;
}
long sum2(int n) //n+2 ==>O(n) 空间复杂度O(1)
{
long ret = 0; //1 4
int i = 0; // 1 4
for (i = 1; i <= n; i++) //n
{
ret += i;
}
return ret;
}
long sum3(int n) // 2 ===>O(1) 空间复杂度O(1)
{
long ret = 0; // 1 4
if (n > 0) // 1
{
ret = (1 + n) * n / 2;
}
return ret;
}
int main()
{
printf("%d\n", sum1(100));
printf("%d\n", sum2(100));
printf("%d\n", sum3(100));
return 0;
}
O ( 1 ) < O ( l o g ( n ) ) < O ( n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(log(n))<O(n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(log(n))<O(n)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
1 线性表
线性表(List)是零个或多个数据元素的集合
线性表中的数据元素之间是有顺序的
线性表中的数据元素个数是有限的
线性表中的数据元素的类型必须相同
1 线性表顺序存储
优点:
无需为线性表中的逻辑关系增加额外的空间
可以快速的获取表中合法位置的元素
缺点:
插入和删除操作需要移动大量元素
当线性表长度变化较大时难以确定存储空间的容量
C语言实现
seqlist.h
#ifndef __MY_SEQLIST_H__
#define __MY_SEQLIST_H__
typedef void SeqList;
typedef void SeqListNode;
// 创建并且返回一个空的线性表
SeqList* SeqList_Create(int capacity);
// 销毁一个线性表list
void SeqList_Destory(SeqList* list);
// 将一个线性表list中的所有元素清空,线性表回到创建时的初始状态
void SeqList_Clear(SeqList* list);
// 返回一个线性表list中的元素个数
int SeqList_Length(SeqList* list);
int SeqList_Capacity(SeqList* list);
// 向一个线性表list的pos位置中插入新元素node
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos);
// 获取一个线性表list的pos位置处的元素
SeqListNode* SeqList_Get(SeqList* list, int pos);
// 删除一个线性表list的pos处元素,返回值为被删除的元素,NULL表示删除失败
SeqListNode* SeqList_Delete(SeqList* list, int pos);
#endif
seqlist.c
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include"seqlist.h"
//结构体套一级指针
typedef struct _tag_SeqList {
int length;
int capacity;
// unsigned int* node; // int *node[] 指针数组
unsigned int ** node;
}TSeqList;
SeqList* SeqList_Create(int capacity) {
TSeqList* tmp = NULL;
tmp = (TSeqList*)malloc(sizeof(TSeqList));
if (tmp == NULL) {
printf("func SeqList_Create() error");
return NULL;
}
memset(tmp, 0, sizeof(TSeqList));
//根据capacity大小分配节点空间
// tmp->node = (unsigned int*)malloc(sizeof(unsigned int*) * capacity);
tmp->node = (unsigned int**)malloc(sizeof(unsigned int*) * capacity);
if (tmp->node == NULL) {
printf("func SeqList_Create() tmp->node error ");
return NULL;
}
tmp->capacity = capacity;
tmp->length = 0;
return tmp;
}
// 销毁一个线性表list
void SeqList_Destory(SeqList* list) {
TSeqList* tlist = NULL;
if (list == NULL) {
return;
}
tlist = (TSeqList*)list;
if (tlist->node != NULL) {
free(tlist->node);
}
free(tlist);
}
// 将一个线性表list中的所有元素清空,线性表回到创建时的初始状态
void SeqList_Clear(SeqList* list) {
TSeqList* tlist = NULL;
if (list == NULL) {
return;
}
tlist = (TSeqList*)list;
tlist->length = 0;
}
// 返回一个线性表list中的元素个数
int SeqList_Length(SeqList* list) {
TSeqList* tlist = NULL;
if (list == NULL) {
return -1;
}
tlist = (TSeqList*)list;
return tlist->length;
}
int SeqList_Capacity(SeqList* list) {
TSeqList* tlist = NULL;
if (list == NULL) {
return -1;
}
tlist = (TSeqList*)list;
return tlist->capacity;
}
// 向一个线性表list的pos位置中插入新元素node
int SeqList_Insert(SeqList* list, SeqListNode* node, int pos) {
int i = 0, ret = 0;
TSeqList* tlist = NULL;
if (list == NULL || node==NULL || pos < 0) {
ret = -1;
printf("SeqList_Insert() error : %d\n", ret);
return ret;
}
tlist = (TSeqList*)list;
//判断是不是链表空间满了
if (tlist->length == tlist->capacity) {
ret = -2;
printf("SeqList_Insert() tlist->length == tlist->capacity error : %d\n", ret);
return ret;
}
// 容错修正 长度为6,容量为20, 在pos=10插入,可以改为插入7位置
if (pos >= tlist->length) {
pos = tlist->length;
}
// 元素后移
for (i = tlist->length; i > pos; i--) {
tlist->node[i] = tlist->node[i-1];
}
// 元素插入
// tlist->node[i] = (unsigned int*)node;
tlist->node[i] = node;
tlist->length++;
return 0;
}
// 获取一个线性表list的pos位置处的元素
SeqListNode* SeqList_Get(SeqList* list, int pos) {
int i = 0;
SeqListNode* ret = 0;
TSeqList* tlist = NULL;
if (list == NULL || pos < 0) {
printf("SeqList_Get() error : %d\n", ret);
return NULL;
}
tlist = (TSeqList*)list;
ret = (SeqListNode*)tlist->node[pos];
return ret;
}
// 删除一个线性表list的pos处元素,返回值为被删除的元素,NULL表示删除失败
SeqListNode* SeqList_Delete(SeqList* list, int pos) {
int i = 0;
SeqListNode* ret = 0;
TSeqList* tlist = NULL;
if (list == NULL || pos < 0) {
printf("SeqList_Delete() error : %d\n", ret);
return NULL;
}
tlist = (TSeqList*)list;
ret = (SeqListNode*)tlist->node[pos];
for (i = pos + 1; i < tlist->length; i++) {
tlist->node[i-1] = tlist->node[i];
}
tlist->length--;
return ret;
}
main
#include<stdlib.h>
#include<stdio.h>
#include<string.h> // c语言中要写.h,不然会报错
#include"seqlist.h"
typedef struct Teacher
{
int age;
char name[64];
}Teacher;
void main() {
int ret = 0;
int i = 0;
SeqList* list = NULL;
Teacher t1, t2, t3, t4, t5;
t1.age = 21;
t2.age = 22;
t3.age = 23;
t4.age = 24;
t5.age = 25;
list = SeqList_Create(10);
if (list == NULL) {
printf("func SeqList_Create() ret %d \n", ret);
return ret;
}
ret = SeqList_Insert(list, (SeqListNode*)& t1, 0); // 头插法
ret = SeqList_Insert(list, (SeqListNode*)& t2, 0); // 头插法
ret = SeqList_Insert(list, (SeqListNode*)& t3, 0); // 头插法
ret = SeqList_Insert(list, (SeqListNode*)& t4, 0); // 头插法
ret = SeqList_Insert(list, (SeqListNode*)& t5, 0); // 头插法
// 遍历
for (i = 0; i < SeqList_Length(list); i++) {
Teacher* tmp = (Teacher*)SeqList_Get(list, i);
if (tmp == NULL) {
return;
}
printf("tmp->age:%d\n", tmp->age);
}
// 删除链表中节点
while (SeqList_Length(list) > 0) {
SeqList_Delete(list, 0);
}
}
结果
tmp->age:25
tmp->age:24
tmp->age:23
tmp->age:22
tmp->age:21
2 线性表链式存储
采用通用链表的方式,用数据结构包含链表
blog.csdnimg.cn/d988ebafe9e14931b03633e79afc11b0.png#pic_center)
1 单向链表
LinkList添加示意图
LinkList删除示意图
linklist.h
#ifndef _MYLINKLIST_H_
#define _MYLINKLIST_H_
typedef void LinkList;
/*
typedef struct _tag_LinkListNode LinkListNode;
struct _tag_LinkListNode{
LinkListNode *next;
}
*/
typedef struct _tag_LinkListNode {
struct _tag_LinkListNode* next;
}LinkListNode;
LinkList* LinkList_Create();
void LinkList_Destory(LinkList* list);
void LinkList_Clear(LinkList* list);
int LinkList_Length(LinkList* list);
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos);
LinkListNode* LinkList_Get(LinkList* list, int pos);
LinkListNode* LinkList_Delete(LinkList* list, int pos);
#endif
linklist.c
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include"linklist.h"
typedef struct _tag_LinkList {
LinkListNode head;
int length;
}TLinkList;
LinkList* LinkList_Create() {
TLinkList* ret = NULL;
ret = (TLinkList*)malloc(sizeof(TLinkList));
memset(ret, 0, sizeof(TLinkList));
ret->length = 0;
ret->head.next = NULL;
return ret;
}
void LinkList_Destory(LinkList* list) {
if (list != NULL) {
free(list);
list = NULL;
}
return;
}
// 让链表变为初始值
void LinkList_Clear(LinkList* list) {
TLinkList* tList = 0;
if (list == NULL) {
return;
}
tList = (TLinkList*)list;
tList->length = 0;
tList->head.next = NULL;
return;
}
int LinkList_Length(LinkList* list) {
TLinkList* tList = 0;
if (list == NULL) {
return;
}
tList = (TLinkList*)list;
return tList->length;
}
int LinkList_Insert(LinkList* list, LinkListNode* node, int pos) {
int ret = 0, i = 0;
TLinkList* tList = NULL;
LinkListNode* current = NULL;
if (list == NULL || node == NULL || pos < 0) {
ret = -1;
printf("LinkList_Insert error %d\n",ret);
return ret;
}
tList = (TLinkList*)list;
current = &(tList->head);
for (i = 0; i < pos && current->next != NULL; i++) {
current = current->next;
}
// 1 node连接后续链表
node->next = current->next;
// 2 前面链表连接新的链表
current->next = node;
tList->length++;
return ret;
}
LinkListNode* LinkList_Get(LinkList* list, int pos) {
int i = 0;
TLinkList* tList = NULL;
LinkListNode* current = NULL;
if (list == NULL || pos < 0) {
printf("LinkList_Get error %d\n");
return NULL;
}
tList = (TLinkList*)list;
current = &(tList->head); //辅助指针变量指向链表头部
for (i = 0; i < pos && current->next != NULL; i++) {
current = current->next;
}
return current->next;
}
LinkListNode* LinkList_Delete(LinkList* list, int pos) {
int i = 0;
TLinkList* tList = NULL;
LinkListNode* current = NULL;
LinkListNode* ret = NULL;
if (list == NULL || pos < 0) {
printf("LinkList_Delete error \n");
return NULL;
}
tList = (TLinkList*)list;
current = &(tList->head);
for (i = 0; i < pos && current->next != NULL; i++) {
current = current->next;
}
// 缓存被删除节点
ret = current->next;
current->next = ret->next;
tList->length--;
return ret;
}
线性表链式存储继承测试.c
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include"linklist.h"
typedef struct Teacher {
LinkListNode node;
int age;
char name[32];
}Teacher;
void main() {
int ret = 0, len = 0, i = 0;
LinkList* list = NULL;
Teacher t1, t2, t3, t4, t5;
t1.age = 21;
t2.age = 22;
t3.age = 23;
t4.age = 24;
t5.age = 25;
list = LinkList_Create();
if (list == NULL) {
return;
}
len = LinkList_Length(list);
ret = LinkList_Insert(list, (LinkListNode*)& t1, 0); //头插法
ret = LinkList_Insert(list, (LinkListNode*)& t2, 0); //头插法
ret = LinkList_Insert(list, (LinkListNode*)& t3, 0); //头插法
ret = LinkList_Insert(list, (LinkListNode*)& t4, 0); //头插法
ret = LinkList_Insert(list, (LinkListNode*)& t5, 0); //头插法
// 遍历
for (i = 0; i < LinkList_Length(list); i++) {
Teacher* tmp = (Teacher *)LinkList_Get(list, i);
if (tmp == NULL) {
return;
}
printf("tmp->age:%d\n", tmp->age);
}
printf("删除链表\n");
// 删除链表
while (LinkList_Length(list) > 0) {
Teacher* tmp = LinkList_Delete(list, 0);
if (tmp == NULL) {
return;
}
printf("tmp->age:%d\n", tmp->age);
}
LinkList_Destory(list);
}
结果
tmp->age:25
tmp->age:24
tmp->age:23
tmp->age:22
tmp->age:21
删除链表
tmp->age:25
tmp->age:24
tmp->age:23
tmp->age:22
tmp->age:21
2 循环链表
CircleList.h
#ifndef _CIRCLE_LIST_H
#define _CIRCLE_LIST_H
//自定义循环链表数据类型
typedef void CircleList;
//自定义循环链表节点数据类型
typedef struct tag_CirclListNode
{
struct tag_CirclListNode *next;
}CircleListNode;
//创建结构体管理链表
typedef struct tag_CircleList
{
//循环链表头结点
CircleListNode header;
//循环链表游标
CircleListNode *slider;
//循环链表长度
int length;
}TCircleList;
//创建循环链表
CircleList* CircleList_Create();
//销毁循环链表
void CircleList_Destroy(CircleList* list);
//清空循环链表
void CircleList_Clear(CircleList* list);
//获取循环链表长度
int CircleList_Length(CircleList* list);
//在循环链表中插入新节点
int CircleList_Insert(CircleList* list, CircleListNode* node, int pos);
//获取循环链表中的指定位置的节点
CircleListNode* CircleList_Get(CircleList* list, int pos);
//删除循环链表中的指定位置的节点
CircleListNode* CircleList_Delete(CircleList* list, int pos);
//------------------ new add ------------------
//直接指定删除链表中的某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
//将游标重置指向链表中的第一个数据元素
CircleListNode* CircleList_Reset(CircleList* list);
//获取当前游标指向的数据元素
CircleListNode* CircleList_Current(CircleList* list);
//将游标移动指向到链表中的下一个数据元素
CircleListNode* CircleList_Next(CircleList* list);
#endif //_CIRCLE_LIST_H
CircleList.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CircleList.h"
//创建循环链表
CircleList* CircleList_Create()
{
//定义TCircleList指针变量,并分配内存空间
TCircleList* tlist = (TCircleList*)malloc(sizeof(TCircleList));
if (tlist == NULL)
{
printf("error: TCircleList* tlist = (TCircleList*)malloc(sizeof(TCircleList)) \n");
return NULL;
}
//数据初始化
tlist->header.next = NULL;
tlist->slider = NULL;
tlist->length = 0;
return (CircleList*)tlist;
}
//销毁循环链表
void CircleList_Destroy(CircleList* list)
{
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL)
{
printf("Destory error: list 为无效指针\n");
return;
}
free(list);
}
//清空循环链表
void CircleList_Clear(CircleList* list)
{
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL)
{
printf("Clear error: list 为无效指针\n");
return;
}
//类型转换并赋值
tlist = (TCircleList*)list;
//将长度重置为0
tlist->length = 0;
//头结点指针域指向空
tlist->header.next = NULL;
//游标指向空
tlist->slider = NULL;
}
//获取循环链表长度
int CircleList_Length(CircleList* list)
{
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL)
{
printf("Length error: list 为无效指针\n");
return -1;
}
//类型转换并赋值
tlist = (TCircleList*)list;
return tlist->length;
}
//在循环链表中插入新节点
int CircleList_Insert(CircleList* list, CircleListNode* node, int pos)
{
int i;
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//定义辅助指针变量
CircleListNode *currentNode = NULL;
//判断list是否为有效指针
if (list == NULL || node == NULL || pos < 0)
{
printf("Insert error: if (list == NULL || node == NULL || pos < 0)\n");
return -1;
}
//类型转换并赋值
tlist = (TCircleList*)list;
//元素插入
//step 1: 使用辅助指针变量,指向头结点
currentNode = &tlist->header;
//step 2: 找到pos-1位置节点
for (i = 0; i < pos; ++i)
{
//判断是否有后继节点
if (currentNode->next != NULL)
{
//指针后移
currentNode = currentNode->next;
}
else
{
//没有后继节点跳出循环
break;
}
}
//step 3: 将node节点的指针指向当前节点(pos-1)的后继节点(pos)
node->next = currentNode->next;
//step 4: 当前节点的指针指向node节点的地址
currentNode->next = node;
//step 5: 如果是第一次插入节点
if (tlist->length == 0)
{
//将游标指向新插入节点
tlist->slider = node;
}
//step 6: 链表长度加1
tlist->length++;
//step 7:若头插法 currentNode仍然指向头部
//原因: 跳0步, 没有跳走
if (currentNode == &tlist->header)
{
CircleListNode* lastNode = CircleList_Get(list, tlist->length - 1);
//最后一个节点的指针,指向第一个数据节点
lastNode->next = currentNode->next;
}
return 0;
}
//获取循环链表中的指定位置的节点
CircleListNode* CircleList_Get(CircleList* list, int pos)
{
int i;
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//定义辅助指针变量
CircleListNode *currentNode = NULL;
//判断list是否为有效指针
if (list == NULL || pos < 0)
{
printf("CircleList_Get error: if (list == NULL || pos < 0)\n");
return NULL;
}
//类型转换并赋值
tlist = (TCircleList*)list;
//step 1: 使用辅助指针变量,指向头结点
currentNode = &tlist->header;
//step 2: 找到pos位置节点
for (i = 0; i <= pos; ++i)
{
//判断是否有后继节点
if (currentNode->next != NULL)
{
//指针后移
currentNode = currentNode->next;
}
else
{
//没有后继节点跳出循环
printf("error: 没找到指定位置的元素\n");
return NULL;
}
}
return currentNode;
}
//删除循环链表中的指定位置的节点
//-------------------------------
CircleListNode* CircleList_Delete(CircleList* list, int pos)
{
int i;
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//定义链表节点指针,保存要删除的节点地址
CircleListNode *deleteNode = NULL;
//定义链表节点指针,保存最后一个节点
CircleListNode *lastNode = NULL;
//定义辅助指针变量
CircleListNode *currentNode = NULL;
//判断list是否为有效指针
if (list == NULL || pos < 0)
{
printf("CircleList_Delete error: if (list == NULL || pos < 0)\n");
return NULL;
}
//类型转换并赋值
// tlist = (TCircleList*)list->header; // list 和 list->header的地址重叠
tlist = (TCircleList*)list;
//判断链表中是否有节点
if (tlist->length <= 0)
{
printf("error: 链表为空,不能删除\n");
return NULL;
}
//元素删除
//step 1: 辅助指针变量,指向头结点
currentNode = &tlist->header;
//step 2: 找到pos-1位置节点
for (i = 0; i < pos; ++i)
{
//指针后移
currentNode = currentNode->next;
}
//step 3: 保存要删除的节点的地址
deleteNode = currentNode->next;
//step 4-1: 判断删除的元素是否为第一个元素
if (currentNode == &tlist->header)
{
//step 4-2: 找到最后一个节点
lastNode = CircleList_Get(list, tlist->length - 1);
}
//step 4-3: 判断lastNode是否为空
if (lastNode != NULL)
{
//step 4-4: 将最后一个节点的地址指向要删除节点的后继节点
lastNode->next = deleteNode->next;
}
//step 4-5: 将头结点的指针指向要删除节点的后继节点
currentNode->next = deleteNode->next;
//step 5: 链表长度减1
tlist->length--;
//step 6-1: 判断删除的元素是否为游标指向的元素
if (tlist->slider == deleteNode)
{
//step 6-2: 游标后移
tlist->slider = deleteNode->next;
}
//step 7-1: 判断删除元素后,链表长度是否为零
if (tlist->length == 0)
{
//step 7-2: 链表头结点指针域指向空
tlist->header.next = NULL;
//step 7-3: 链表游标指向空
tlist->slider = NULL;
}
return deleteNode;
}
//------------------ new add ------------------
//直接指定删除链表中的某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node)
{
int i;
int nPos = 0;
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL || node == NULL)
{
printf("CircleList_DeleteNode error: if (list == NULL || node == NULL)\n");
return NULL;
}
//类型转换并赋值
tlist = (TCircleList*)list;
//定义辅助指针变量,指向头结点
CircleListNode* currentNode = &tlist->header;
//定义辅助指针变量,用来保存要删除的节点地址
CircleListNode* delNode = NULL;
//查找node节点在循环链表中的位置
for (i = 0; i < tlist->length; ++i)
{
//从第一个数据节点开始判断,查找等于node的节点
if (currentNode->next == node)
{
//保存与node节点相等的节点的位置
nPos = i;
//保存要删除的节点地址
delNode = currentNode->next;
//跳出循环
break;
}
//当前节点指针后移
currentNode = currentNode->next;
}
//如果找到delNode,根据nPos删除该节点
if (delNode != NULL)
{
//删除指定位置的元素
CircleList_Delete(list, nPos);
}
return delNode;
}
//将游标重置指向链表中的第一个数据元素
CircleListNode* CircleList_Reset(CircleList* list)
{
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL)
{
printf("CircleList_Reset error: if (list == NULL)\n");
return NULL;
}
//类型转换并赋值
tlist = (TCircleList*)list;
//重置游标位置
tlist->slider = tlist->header.next;
return tlist->slider;
}
//获取当前游标指向的数据元素
CircleListNode* CircleList_Current(CircleList* list)
{
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL)
{
printf("CircleList_Current error: if (list == NULL)\n");
return NULL;
}
//类型转换并赋值
tlist = (TCircleList*)list;
return tlist->slider;
}
//将游标移动指向到链表中的下一个数据元素
CircleListNode* CircleList_Next(CircleList* list)
{
//定义链表节点指针变量
CircleListNode *currNode = NULL;
//定义TCircleList指针变量
TCircleList *tlist = NULL;
//判断list是否为有效指针
if (list == NULL)
{
printf("CircleList_Next error: if (list == NULL)\n");
return NULL;
}
//类型转换并赋值
tlist = (TCircleList*)list;
//存储当前游标位置
currNode = tlist->slider;
//判断当前游标是否指向空
if (tlist->slider != NULL)
{
//游标后移
tlist->slider = currNode->next;
}
return currNode;
}
demo01_循环链表基本功能测试.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CircleList.h"
typedef struct tag_value
{
CircleListNode circleNode;
int v;
}Value;
#if 0
int main()
{
int i;
//定义Value结构体数组
Value val[10]; //创建循环链表
CircleList* list = CircleList_Create();
//循环初始化数组
for (i = 0; i < sizeof(val) / sizeof(Value); ++i)
{
val[i].v = i + 20;
//往循环链表中插入数据
CircleList_Insert(list, (CircleListNode*)&val[i], i);
}
//遍历循环链表
//************* 怎么证明是循环链表? *************
for (i = 0; i < CircleList_Length(list) * 2; ++i) //打印两遍
{
Value *pVal = (Value*)CircleList_Get(list, i);
printf("Value %d = %d\n", i, pVal->v);
}
//删除节点
while (CircleList_Length(list) > 0)
{
Value *pVal = (Value*)CircleList_Delete(list, 0);
printf("Delete Value: val = %d\n", pVal->v);
}
//销毁循环链表
CircleList_Destroy(list);
return 0;
}
#endif
结果
Value 0 = 20
Value 1 = 21
Value 2 = 22
Value 3 = 23
Value 4 = 24
Value 5 = 25
Value 6 = 26
Value 7 = 27
Value 8 = 28
Value 9 = 29
Value 10 = 20
Value 11 = 21
Value 12 = 22
Value 13 = 23
Value 14 = 24
Value 15 = 25
Value 16 = 26
Value 17 = 27
Value 18 = 28
Value 19 = 29
Delete Value: val = 20
Delete Value: val = 21
Delete Value: val = 22
Delete Value: val = 23
Delete Value: val = 24
Delete Value: val = 25
Delete Value: val = 26
Delete Value: val = 27
Delete Value: val = 28
Delete Value: val = 29
demo02_约瑟夫问题求解.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "circlelist.h"
/*
约瑟夫问题-循环链表典型应用
n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,
报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报
到第 m 个人,再令其出列,…,如此下去,求出列顺序。
求解: 假设 m = 3, n = 8 (1 2 3 4 5 6 7 8)
结果: 3 6 1 5 2 8 4 7
*/
#if 0
//定义结构体,存储数据
typedef struct tag_value
{
CircleListNode header;
int v;
}Value;
void joseph_question()
{
int i;
//定义结构体数组
Value val[8];
//创建循环链表
CircleList* list = CircleList_Create();
//判断链表是否创建成功
if (list == NULL)
{
printf("链表创建失败\n");
return;
}
//初始化结构体数组
for (i = 0; i < sizeof(val) / sizeof(Value); ++i)
{
val[i].v = i+1;
//往循环链表中插入数据
CircleList_Insert(list, (CircleListNode*)&val[i], i);
}
//遍历循环链表
printf("插入数据:\n");
for (i = 0; i < CircleList_Length(list); ++i)
{
//获取游标指向的元素然后下移
Value* pVal = (Value*)CircleList_Get(list, i);
printf("%d\t", pVal->v);
}
//重置游标
CircleList_Reset(list);
//循环删除指定位置的元素
printf("\n\n依次删除的节点为:\n");
while (CircleList_Length(list) > 0)
{
//定义结构体指针变量,指向符合条件的元素
Value* pVal = NULL;
//根据条件查找指定位置的元素
for (i = 0; i < 3-1; ++i) //3为案例中的m
{
//向后移动游标
pVal = (Value*)CircleList_Next(list);
}
//保存符合条件的节点
pVal = (Value*)CircleList_Current(list);
//打印节点信息
printf("%d\t", pVal->v);
//从链表中删除符合条件的节点
CircleList_DeleteNode(list, (CircleListNode*)pVal);
}
printf("\n");
//销毁循环链表
CircleList_Destroy(list);
}
#else
// 定义数据结构
// 业务节点的定义
typedef struct _Value
{
// 内部的链表节点
CircleListNode node;
int v; // 数据
}Value;
void joseph_question()
{
Value val[8];
// 创建循环链表
CircleList *list = CircleList_Create();
// 初始化数组
for (int i = 0; i < 8; ++i)
{
val[i].v = i + 1;
// 节点插入到链表
CircleList_Insert(list, &val[i].node, i);
//CircleList_Insert(list, (CircleListNode*)&val[i], i);
}
// 遍历
for (int i = 0; i < CircleList_Length(list); ++i)
{
Value* p = (Value*)CircleList_Get(list, i);
printf("%d ", p->v);
}
printf("\n");
// 出链表操作
// 游标重置, 指向第一个数据节点
printf("删除的节点的次序\n");
CircleList_Reset(list);
while (CircleList_Length(list))
{
// 游标后移的步长
for (int i = 0; i < 2; ++i)
{
// 游标后移
CircleList_Next(list);
}
// 获取当前游标指向的节点
Value* p = (Value*)CircleList_Current(list);
//
printf("%d ", p->v);
// 删除当前节点
CircleList_DeleteNode(list, (CircleListNode*)p);
}
CircleList_Destroy(list);
}
#endif
#if 1
void main()
{
joseph_question();
system("pause");
}
#endif
结果
1 2 3 4 5 6 7 8
删除的节点的次序
3 6 1 5 2 8 4 7
3 双向链表
DLinkList.h
#ifndef _DLINK_LIST_H
#define _DLINK_LIST_H
//自定义双向链表数据类型
typedef void DLinkList;
//自定义双向链表节点数据类型
typedef struct tag_dLinkListNode
{
struct tag_dLinkListNode *prev;
struct tag_dLinkListNode *next;
}DLinkListNode;
//定义管理双向链表的结构体
typedef struct _tag_dlinklist
{
DLinkListNode head;
DLinkListNode *slider;
int length;
}TDLinkList;
//创建链表
DLinkList* DLinkList_Create();
//销毁链表
void DLinkList_Destroy(DLinkList* list);
//清空链表
void DLinkList_Clear(DLinkList* list);
//获取链表长度
int DLinkList_Length(DLinkList* list);
//获取第pos个元素操作
DLinkListNode* DLinkList_Get(DLinkList* list, int pos);
//插入元素到位置pos
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos);
//删除位置pos处的元素
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos);
//获取当前游标指向的数据元素
DLinkListNode* DLinkList_Current(DLinkList* list);
//将游标重置指向链表中的第一个数据元素
DLinkListNode* DLinkList_Reset(DLinkList* list);
//将游标移动指向到链表中的下一个数据元素
DLinkListNode* DLinkList_Next(DLinkList* list);
//将游标移动指向到链表中的上一个数据元素
DLinkListNode* DLinkList_Prev(DLinkList* list);
//直接指定删除链表中的某个数据元素
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node);
#endif //_DLINK_LIST_H
DLinkList.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DLinkList.h"
//创建链表
DLinkList* DLinkList_Create()
{
//定义结构体类型指针变量,并分配内存空间
TDLinkList* dlist = (TDLinkList*)malloc(sizeof(TDLinkList));
//如果分配内存成功,则初始化变量
if (dlist != NULL)
{
dlist->head.next = NULL;
dlist->slider = NULL;
dlist->length = 0;
return (DLinkList*)dlist;
}
//失败返回空
printf("分配内存失败\n");
return NULL;
}
//销毁链表
void DLinkList_Destroy(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//释放内存空间
free(list);
}
}
//清空链表
void DLinkList_Clear(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//数据重置
dlist->length = 0;
dlist->head.next = NULL;
dlist->slider = NULL;
}
}
//获取链表长度
int DLinkList_Length(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
return dlist->length;
}
printf("DLinkList_Length error: list 指针无效\n");
return -1;
}
//获取第pos个元素操作
DLinkListNode* DLinkList_Get(DLinkList* list, int pos)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//定义辅助指针变量, 并初始化,指向头节点
DLinkListNode* currNode = &dlist->head;
//循环查找pos位置元素
for (int i = 0; i <= pos; ++i)
{
currNode = currNode->next;
}
return currNode;
}
printf("DLinkList_Get error: list 指针无效\n");
return NULL;
}
//插入元素到位置pos
int DLinkList_Insert(DLinkList* list, DLinkListNode* node, int pos)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//定义辅助指针变量, 并初始化,指向头节点
DLinkListNode* currNode = &dlist->head;
//定义辅助指针变量
DLinkListNode* posNode = NULL;
//循环查找pos-1位置元素
for (int i = 0; i < pos; ++i)
{
//判断是否有后继节点
if (currNode->next != NULL)
{
//指针后移
currNode = currNode->next;
}
else
{
//没有后继节点,结束循环
break;
}
}
//赋值,辅助指针变量指向pos位置节点
posNode = currNode->next;
//开始插入元素
//step1: 将新节点的next域指针指向pos位置节点的地址
node->next = posNode;
//step2: 将当前节点的next域指针指向新插入节点的地址
currNode->next = node;
//step3: 将pos位置的节点的prev域指针指向新插入节点的地址
//********** 特殊处理 **********
if (posNode != NULL) //当链表插入第一个元素需要特殊处理
{
posNode->prev = node;
}
//step4: 将新插入节点的地址指向当前节点的地址
node->prev = currNode;
//********** 特殊处理 **********
if (currNode == &dlist->head) //如果链表为空
{
//将第一个节点的前驱节点设为空
node->prev = NULL;
//游标指向第一个节点
dlist->slider = node;
}
//step4: 链表长度加1
dlist->length++;
return 0;
}
printf("DLinkList_Insert error: list 指针无效\n");
return -1;
}
//删除位置pos处的元素
DLinkListNode* DLinkList_Delete(DLinkList* list, int pos)
{
//判断list是否为有效指针
if (list != NULL && pos >= 0)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//定义辅助指针变量, 并初始化,指向头节点
DLinkListNode* currNode = &dlist->head;
//定义辅助指针变量
DLinkListNode* delNode = NULL;
DLinkListNode* nextNode = NULL;
//循环查找pos-1位置元素
for (int i = 0; i < pos; ++i)
{
currNode = currNode->next;
}
//赋值
delNode = currNode->next;
nextNode = delNode->next;
//开始删除元素
//step1: 将当前节点的next域指针指向被删除节点的后继节点
currNode->next = nextNode;
//****** 需要特殊处理 ******
if (nextNode != NULL)
{
//step2: nextNode节点的prev域指针指向当前节点的地址
nextNode->prev = currNode;
//****** 需要特殊处理 ******
if (currNode == &dlist->head) //如果当前节点为头结点
{
//将nextNode节点指向空
nextNode->prev = NULL;
}
}
//step 3: 链表长度减1
dlist->length--;
//判断删除的元素是不是当前游标指向的位置
if (dlist->slider == delNode)
{
//如果是,游标后移
dlist->slider = nextNode;
}
return delNode;
}
printf("DLinkList_Delete error: list指针 或 pos位置无效\n");
return NULL;
}
//获取当前游标指向的数据元素
DLinkListNode* DLinkList_Current(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
return dlist->slider;
}
printf("DLinkList_Current error: list 指针无效\n");
return NULL;
}
//将游标重置指向链表中的第一个数据元素
DLinkListNode* DLinkList_Reset(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
dlist->slider = dlist->head.next;
return dlist->slider;
}
printf("DLinkList_Reset error: list 指针无效\n");
return NULL;
}
//将游标移动指向到链表中的下一个数据元素
DLinkListNode* DLinkList_Next(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//定义链表节点指针保存当前游标地址
DLinkListNode* currSlider = dlist->slider;
//游标后移
if (dlist->slider->next != NULL)
{
dlist->slider = dlist->slider->next;
return currSlider;
}
else
{
return NULL;
}
}
printf("DLinkList_Next error: list 指针无效\n");
return NULL;
}
//将游标移动指向到链表中的上一个数据元素
DLinkListNode* DLinkList_Prev(DLinkList* list)
{
//判断list是否为有效指针
if (list != NULL)
{
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//定义链表节点指针保存当前游标地址
DLinkListNode* currSlider = dlist->slider;
//游标前移
dlist->slider = dlist->slider->prev;
return currSlider;
}
printf("DLinkList_Prev error: list 指针无效\n");
return NULL;
}
//直接指定删除链表中的某个数据元素
DLinkListNode* DLinkList_DeleteNode(DLinkList* list, DLinkListNode* node)
{
//判断list是否为有效指针
if (list != NULL)
{
int nPos = 0;
//定义结构体类型指针,并给其赋值
TDLinkList* dlist = (TDLinkList*)list;
//查找与node节点相等的节点
for (int i = 0; i < dlist->length; ++i)
{
if (node == DLinkList_Get(list, i))
{
//保存位置
nPos = i;
//跳出循环
break;
}
}
//删除指定nPos位置节点
DLinkListNode* delNode = DLinkList_Delete(list, nPos);
return delNode;
}
printf("DLinkList_DeleteNode error: list or node 指针无效\n");
return NULL;
}
双向链表基本功能测试.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DLinkList.h"
//定义数据结构体
typedef struct tag_value
{
//包含双向链表的一个节点
DLinkListNode head;
int value;
}Value;
//双向链表测试程序
void dLinkListTest()
{
int i;
//定义结构体数组
Value val[10];
//创建双向链表
DLinkList *dlist = DLinkList_Create();
//判断是否创建成功
if (dlist == NULL)
{
printf("双向链表创建失败\n");
return;
}
//初始化并向链表中插入数据
for (i = 0; i < sizeof(val) / sizeof(Value); ++i)
{
val[i].value = i + 10;
//向尾部插入元素
DLinkList_Insert(dlist, (DLinkListNode*)&val[i], i);
}
//遍历双向链表
printf("遍历双向链表\n");
for (int i = 0; i < DLinkList_Length(dlist); ++i)
{
//获取指定位置元素
Value* val = (Value*)DLinkList_Get(dlist, i);
printf("%d\t", val->value);
}
printf("\n");
//删除最后一个节点
DLinkList_Delete(dlist, DLinkList_Length(dlist) - 1);
//删除第一节点
DLinkList_Delete(dlist, 0);
//再次遍历链表
printf("再次遍历双向链表\n");
for (int i = 0; i < DLinkList_Length(dlist); ++i)
{
//获取指定位置元素
Value* val = (Value*)DLinkList_Get(dlist, i);
printf("%d\t", val->value);
}
printf("\n");
//重置游标
DLinkList_Reset(dlist);
//游标后移
DLinkList_Next(dlist);
//获取当前游标指向的节点
Value* pVal = (Value*)DLinkList_Current(dlist);
//打印当前节点的value值
printf("DLinkList_Next --- 打印当前节点的value值: value = %d\n", pVal->value);
//删除游标指向的当前节点
DLinkList_DeleteNode(dlist, (DLinkListNode*)pVal);
//再次获取当前游标指向的节点
pVal = (Value*)DLinkList_Current(dlist);
//再次打印当前节点的value值
printf("DLinklist_DeleteNode --- 再次打印当前节点的value值: value = %d\n", pVal->value);
//向前移动游标
DLinkList_Prev(dlist);
//第三次获取当前游标指向的节点
pVal = (Value*)DLinkList_Current(dlist);
//第三次打印当前节点的value值
printf("DLinkList_Prev --- 再次打印当前节点的value值: value = %d\n", pVal->value);
//打印链表的长度
printf("打印链表的长度, Length = %d\n", DLinkList_Length(dlist));
//销毁双向链表
DLinkList_Destroy(dlist);
}
void main()
{
dLinkListTest();
system("pause");
}
结果
遍历双向链表
10 11 12 13 14 15 16 17 18 19
再次遍历双向链表
11 12 13 14 15 16 17 18
DLinkList_Next --- 打印当前节点的value值: value = 12
DLinklist_DeleteNode --- 再次打印当前节点的value值: value = 13
DLinkList_Prev --- 再次打印当前节点的value值: value = 11
打印链表的长度, Length = 7