数据结构(链表)
解决:长度固定的问题,插入和删除麻烦的问题
结构
逻辑结构:线性结构
存储结构:链式存储结构 在内存当中存储是连续的 数组
结构体
typedef int datatype;
typedef struct node_t
{
datatype data;//数据域
struct node_t *next;//指针域,指向自身结构体的指针
}link_node_t,*link_list_t;
创建一个空的单向链表(有头单向链表)
link_node_t *CreateEpLinkList()
{
//思想:创建一个节点,作为头节点
link_list_t p=(link_list_t)malloc(sizeof(link_node_t));
if(p==NULL)
{
perror("CreateEpLinkList err");
return NULL;
}
p->next=NULL;
return p;
}
操作
在指定位置插入
1.容错判断(判越界)
2.创建一个新节点pnew用于存储数据
link_list_t pnew =(link_list_t)malloc(sizeof(link_node_t));
pnew->data=data
3.将头指针移动到插入位置的前一个节点
4.插入操作(先连后面再连前面)
求链表长度:(有头遍历)
int LengthLinkList(link_node_t *p)
{
int len=0;
while(p->next !=NULL)
{
p=p->next;
len++;
}
return len;
}
容错判断:
if(post<0|| post>LengthLinkList(p))
{
perror("InsertIntoPostLinkList err");
return -1;
}
将头指针遍历到插入位置的前一个节点:
for (int i = 0; i < post; i++)
{
p=p->next;
}
插入操作:
pnew->data=data;
pnew->next ==NULL;
pnew->next =p->next;
p->next=pnew;
分段代码:
//向单向链表的指定位置插入数据
//p 保存链表的头指针 post 插入的位置 data 插入的数据
int InsertIntoPostLinkList(link_node_t *p,int post, datatype data)
{
link_list_t pnew = NULL;
//1.容错判断
if(post<0|| post>LengthLinkList(p))
{
perror("InsertIntoPostLinkList err");
return -1;
}
//2.将头指针移动到插入位置的前一个节点
for (int i = 0; i < post; i++)
{
p=p->next;
}
//3.创建新节点保存插入数据
pnew =(link_list_t)malloc(sizeof(link_node_t));
if(pnew ==NULL)
{
perror("pnew malloc err");
return -1;
}
pnew->data=data;
pnew->next ==NULL;
//4.将新节点插入指定位置
pnew->next =p->next;
p->next=pnew;
return 0;
}
删除指定位置的数据
1.容错判断(判越界、判空)
2.创建一个删除指针pdel
3.定位到删除位置的前一个节点
4.删除操作
判断单向链表是否为空 1 代表空 0 代表非空
判断单向链表是否为空 1 代表空 0 代表非空
int IsEpLinkList(link_node_t *p)
{
return p->next==NULL;
}
容错判断:
if(post<0 || post>=LengthLinkList(p) || IsEpLinkList(p))
{
perror("DeletePostLinkList err");
return -1;
}
将头指针遍历到删除位置的前一个节点:
for(int i=0;i<post;i++)
{
p=p->next;
}
删除操作:
pdel=p->next;
//跨过被删除节点
p->next = pdel->next;
//释放被删除节点
free(pdel);
pdel=NULL;
分段代码
删除单向链表中指定位置的数据 post 代表的是删除的位置
int DeletePostLinkList(link_node_t *p, int post)
{
//1.容错判断
if(post<0 || post>=LengthLinkList(p) || IsEpLinkList(p))
{
perror("DeletePostLinkList err");
return -1;
}
//2.遍历到删除位置前一个节点
for(int i=0;i<post;i++)
{
p=p->next;
}
//3.定义一个指针指向被删除节点
link_list_t pdel=p->next;
//4.跨过被删除节点
p->next = pdel->next;
//5.释放被删除节点
free(pdel);
pdel=NULL;
}
删除指定数据
1.定义一个代替指针q指向p的next
定义一个删除指针pdel
2.用q无头遍历
3.if(q->data==data)
执行删除操作
q指针指向下一个节点
p指向下一个节点
q指向p下一个节点
分段代码
//删除单向链表中出现的指定数据,data 代表将单向链表中出现的所有 data 数据删除
int DeleteDataLinkList(link_node_t *p, datatype data)
{
//1.定义指针q,q指向p的next
link_list_t q =p->next;
link_list_t pdel =NULL;
//2.用q遍历无头链表
while(q != NULL)
{
if(q->data == data)
{
pdel=q;//1.将pedl指向被删除节点
p->next=pdel->next;//2.跨过被删除节点
free(pdel);//3.释放被删除节点
pdel=NULL;
q=p->next;//4.q指向链表删除后的下一个节点
}
else
{
p=p->next;//p走向下一个节点
q=p->next;//q重新指向p的下一个节点
}
}
return 0;
}
修改指定位置的数据
1.容错判断(判越界)
2.for遍历到修改节点的位置
3.修改操作
用头指针遍历到修改节点位置:
for(int i=0;i<=post;i++)
{
p=p->next;
}
修改操作:
p->data = data;
分段代码
//修改指定位置的数据 post 被修改的位置 data 修改成的数据
int ChangePostLinkList(link_node_t *p, int post, datatype data)
{
//1.容错判断
if(post<0 || post>=LengthLinkList(p))
{
perror("ChangePostLinkList err");
return -1;
}
//2.遍历到修改的节点位置
for(int i=0;i<=post;i++)
{
p=p->next;
}
//3.修改数据
p->data = data;
return 0;
}
查找指定数据出现的位置
1.定义一个下标指针post
2.有头遍历
3.判断p->data==data
3.计数post++
分段代码
查找指定数据出现的位置 data 被查找的数据 //search 查找
int SearchDataLinkList(link_node_t *p, datatype data)
{
int post =0;
while(p->next != NULL)
{
p=p->next;
if(p->data==data)
return post;
post++;
}
return -1;
}
遍历
1.有头遍历
分段代码
//遍历单向链表
void ShowLinkList(link_node_t *p)
{
p=p->next;
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
转置
1.创建替代指针q
创建临时指针temp存放q的下一个节点
2.断头操作
3.遍历无头链表
4.转置操作(先连后面再连前面)
5.将q指向temp存储的q的下一个节点
断头操作:
p->next=null
转置操作:
q->next=p->next
p->next=q转置操作:
q->next=p->next
p->next=q
分段代码
转置链表
void ReverseLinkList(link_node_t *p)
{
//1.断开前保存头节点的下一个节点的地址
link_list_t q =p->next;
link_list_t temp =NULL;
//2.断开链表
p->next=NULL;
//3.遍历无头链表
while(q != NULL)
{
//提前保存q的下一个节点
temp =q->next;
//先连后面再连前面
q->next=p->next;
p->next=q;
//将q移动到无头链表的下一个节点
q=temp;
}
}
清空链表
1.定义一个删除指针pdel
2.有头遍历
3.清空操作
分段代码
//清空单向链表
void ClearLinkList(link_node_t *p)
{
link_list_t pdel =NULL;
while (p->next !=NULL)//遍历一遍
{
pdel=p->next;//pdel指向当前节点
p->next=pdel->next;//进到下一个节点
//3.释放被删除节点
free(pdel);
pdel=NULL;
}
}
总代码
//1.创建一个空的单向链表(有头单向链表)
link_node_t *CreateEpLinkList()
{
//思想:创建一个节点,作为头节点
link_list_t p=(link_list_t)malloc(sizeof(link_node_t));
if(p==NULL)
{
perror("CreateEpLinkList err");
return NULL;
}
p->next=NULL;
return p;
}
//2.求单向链表长度的函数
int LengthLinkList(link_node_t *p)
{
int len=0;
while(p->next !=NULL)
{
p=p->next;
len++;
}
return len;
}
//3.向单向链表的指定位置插入数据
//p 保存链表的头指针 post 插入的位置 data 插入的数据
int InsertIntoPostLinkList(link_node_t *p,int post, datatype data)
{
link_list_t pnew = NULL;
//1.容错判断
if(post<0|| post>LengthLinkList(p))
{
perror("InsertIntoPostLinkList err");
return -1;
}
//2.将头指针移动到插入位置的前一个节点
for (int i = 0; i < post; i++)
{
p=p->next;
}
//3.创建新节点保存插入数据
pnew =(link_list_t)malloc(sizeof(link_node_t));
if(pnew ==NULL)
{
perror("pnew malloc err");
return -1;
}
pnew->data=data;
pnew->next ==NULL;
//4.将新节点插入指定位置
pnew->next =p->next;
p->next=pnew;
return 0;
}
//4.判断单向链表是否为空 1 代表空 0 代表非空
int IsEpLinkList(link_node_t *p)
{
return p->next==NULL;
}
//5.删除单向链表中指定位置的数据 post 代表的是删除的位置
int DeletePostLinkList(link_node_t *p, int post)
{
//1.容错判断
if(post<0 || post>=LengthLinkList(p) || IsEpLinkList(p))
{
perror("DeletePostLinkList err");
return -1;
}
//2.遍历到删除位置前一个节点
for(int i=0;i<post;i++)
{
p=p->next;
}
//3.定义一个指针指向被删除节点
link_list_t pdel=p->next;
//4.跨过被删除节点
p->next = pdel->next;
//5.释放被删除节点
free(pdel);
pdel=NULL;
}
//6.遍历单向链表
void ShowLinkList(link_node_t *p)
{
p=p->next;
while(p != NULL)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
//7.修改指定位置的数据 post 被修改的位置 data 修改成的数据
int ChangePostLinkList(link_node_t *p, int post, datatype data)
{
//1.容错判断
if(post<0 || post>=LengthLinkList(p))
{
perror("ChangePostLinkList err");
return -1;
}
//2.遍历到修改的节点位置
for(int i=0;i<=post;i++)
{
p=p->next;
}
//3.修改数据
p->data = data;
return 0;
}
//8.查找指定数据出现的位置 data 被查找的数据 //search 查找
int SearchDataLinkList(link_node_t *p, datatype data)
{
int post =0;
while(p->next != NULL)
{
p=p->next;
if(p->data==data)
return post;
post++;
}
return -1;
}
//9.删除单向链表中出现的指定数据,data 代表将单向链表中出现的所有 data 数据删除
int DeleteDataLinkList(link_node_t *p, datatype data)
{
//1.定义指针q,q指向p的next
link_list_t q =p->next;
link_list_t pdel =NULL;
//2.用q遍历无头链表
while(q != NULL)
{
if(q->data == data)
{
pdel=q;//1.将pedl指向被删除节点
p->next=pdel->next;//2.跨过被删除节点
free(pdel);//3.释放被删除节点
pdel=NULL;
q=p->next;//4.q指向链表删除后的下一个节点
}
else
{
p=p->next;//p走向下一个节点
q=p->next;//q重新指向p的下一个节点
}
}
return 0;
}
//10.转置链表
void ReverseLinkList(link_node_t *p)
{
//1.断开前保存头节点的下一个节点的地址
link_list_t q =p->next;
link_list_t temp =NULL;
//2.断开链表
p->next=NULL;
//3.遍历无头链表
while(q != NULL)
{
//提前保存q的下一个节点
temp =q->next;
//先连后面再连前面
q->next=p->next;
p->next=q;
//将q移动到无头链表的下一个节点
q=temp;
}
}
//11.清空单向链表
void ClearLinkList(link_node_t *p)
{
link_list_t pdel =NULL;
while (p->next !=NULL)//遍历一遍
{
pdel=p->next;//pdel指向当前节点
p->next=pdel->next;//进到下一个节点
//3.释放被删除节点
free(pdel);
pdel=NULL;
}
}