链表的定义
链表的定义:
- 在内存上不连续存储(离散的)。
- 通过指针相连接。
- 每个节点前后都连接了一个节点(前面只有一个,后面只有一个)。
总结:
n个节点连续分配,彼此之间通过指针相连接,每个节点都只有一个前驱、后继,首节点没有前驱节点,尾节点没有后续节点。
专业术语:
首节点:第一个有效节点
尾节点:最后一个有效节点
头节点:第一个有效节点之前的节点,头节点并不存放有效数据,加头结点的目的是为了方便对链表的操作;头节点的数据类型和首节点数据类型一致
头指针:指向头节点的指针变量(不是指向首节点)
尾指针:指向尾节点的指针变量
如果希望通过调用一个函数来对链表进行操作,我们最起码需要哪些参数:
只需要一个参数,即头指针,因为我们可以通过头指针找到头结点的地址,只要能够找到头节点就可以找到整个链表的其它所有信息(可以理解为发现了老鼠尾巴就能抓到整只老鼠)。
如图所示
线性链表图
链表的分类
单链表、双链表、循环链表、非循环链表
双链表:每一个节点有两个指针域
循环链表:能通过任何一个节点找到其他节点(类似于蛇咬自己的尾巴,尾节点的指针域返回指向首节点)
算法:遍历、查找、清空、销毁、求长度、排序、删除节点、插入节点
头文件
#ifndef _LB_H_
#define _LB_H_
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct Node
{
int data;
struct Node *pNext;
}Node,*PNode;
PNode create_Node();
void traversal_Node(PNode amns);
bool empty_Node(PNode Node);
void length_Node(PNode Node,int *val);
void sort_Node(PNode Node,int len);
void insert_Node(PNode Node ,int pos,int val);
void delete_Node(PNode Node,int pos,int *);
#endif
函数实现
#include"lb.h"
PNode create_Node()
{
//创建单链表
int len=0;
int val=0;
printf("请输入索要创建的链表个数len= ");
scanf("%d",&len);
PNode Phead=(PNode)malloc(sizeof(Node));
//创建头节点
PNode Pt=Phead;
//创建交换指针
Pt->pNext=NULL;
int i=0;
for(i=0;i<len;i++)
{
printf("请输入所要赋的值val= ");
scanf("%d",&val);
PNode Pnew=(PNode)malloc(sizeof(Node));
//创建动态空间用于存储
if(NULL==Pnew)
//判断空间是否创建成功
{
printf("链表创建失败!");
}
Pnew->data=val;
//将输入的值赋给数据域
Pt->pNext=Pnew;
//使头节点的指针域指向创建的空间
Pt=Pnew;
//使交换指针指向创建的空间
Pt->pNext=NULL;
//使新指向节点的指针域为空(尾指针为空)
}
return Phead;
//将头节点的地址返回
}
void traversal_Node(PNode amns)
//遍历链表
{
PNode p=amns->pNext;
//创建结构体指针指向首节点
while(NULL!=p)
//判断指针指向的下一节点是否为空
{
printf("%d ",p->data);
p=p->pNext;
}
return;
}
bool empty_Node(PNode Node)
//判断头节点是否为空
{
if(NULL==Node->pNext)
{
return true;
}
else
{
return false;
}
}
void length_Node(PNode Node,int *val)
//计算链表的长度,将长度返回给*val
{
int cnt=0;
//cnt为计数器
PNode p=Node->pNext;
//创建结构体指针指向首节点
while(NULL!=p)
{
p=p->pNext;
cnt++;
}
*val=cnt;
return;
}
void sort_Node(PNode Node,int len)
//链表排序
{
int i=0;
int j=0;
int t=0;
//创建循环运行条件及交换变量
PNode a,b;
//创建结构体指针用来指向节点判断数据域值的大小
for(i=0,a=Node->pNext;i<len-1;i++,a=a->pNext)
//思想与数组的排序别无二致,在清楚之前要多想!要多思考!
{
for(j=i+1,b=a->pNext;j<len;j++,b=b->pNext)
{
if(a->data>b->data)
{
t=a->data;
a->data=b->data;
b->data=t;
}
}
}
return;
}
void insert_Node(PNode Nod,int pos,int val)
{
//在pos前插入一个节点,即新节点替代老节点的位置,老节点后移
int i=0;
PNode p=Nod;
//起始位i为0,创建结构体指针指向头节点
while(NULL!=p&&i<pos-1)
//对p指针进行判断,当p指向NULL(尾节点的值或链表为空时)停止
//当i不满足条件时停止
{
p=p->pNext;
i++;
}
if(i>pos-1||p==NULL)
//判断循环结束时的指针和起始位是由什么原因导致结束的
//如果是因为链表条件不满足参数则执行return
{
return;
}
//若条件满足则执行插入节点操作
PNode Pnew=(PNode)malloc(sizeof(Node));
//申请动态空间创建新节点
Pnew->pNext=p->pNext;
p->pNext=Pnew;
Pnew->data=val;
//赋值给新节点
return;
}
void delete_Node(PNode Node,int pos,int *val)
//删除指定位置的节点,操作和插入操作逻辑类似
{
int i=0;
PNode p=Node;
while(NULL!=p&&i<pos-1)
{
p=p->pNext;
i++;
}
if(i>pos-1||NULL==p)
{
printf("所要删除的节点不存在!");
return;
}
PNode Pnew=p->pNext;
//创建结构体指针指向所要删除的节点
*val=Pnew->data;
//将所要删除的值赋给变量
p->pNext=Pnew->pNext;
free(Pnew);
Pnew=NULL;
return;
}
主函数
#include"lb.h"
int main(int argc, const char *argv[])
{
PNode first=NULL;
first=create_Node();
traversal_Node(first);
printf("\n");
if(empty_Node(first))
{
printf("链表为空!\n");
}
else
{
printf("链表不为空!\n");
}
int val=0;
length_Node(first,&val);
printf("链表的长度为%d\n",val);
sort_Node(first,val);
insert_Node(first,1,367);
traversal_Node(first);
delete_Node(first,1,&val);
printf("\n删除的元素为%d\n",val);
traversal_Node(first);
printf("\n");
return 0;
}