单向链表
单向链表:注意和NULL指针的比较
typedef struct list{
int data; //数据区
struct list *next; //地址区
//程序顺序执行,这时不能使用Plist和List *
}List,*Plist;
1.创建头节点
Plist create_list()
{
Plist p=malloc(sizeof(List));//Plist p=(Plist)malloc(sizeof(List))
//void *malloc(size_t size),malloc没有具体类型返回值,要转换后使用,
//有的编译器有隐式转换就可以不写(Plist),但是否具有隐式转换编译器有差异,没有的写(Plist)
if(NULL==p) //判断头节点是否创建成功
{
puts("create err");
return NULL;
}
p->next=NULL; //防止野指针
}
2.插入(头插)
int insert_head(Plist P) //链表插入(头插法)
{
if(NULL==p)
return -1;
Plist q=malloc(sizeof(List)); //新建一个要插入的节点
if(NULL==q)
{
puts("malloc err");
return -1;
}
q->next=p->next; //17、18行不能交换顺序,否则会造成内存泄漏
p->next=q;
return 0;
}
(尾插)
int insert_tail(Plist p)
{
if(NULL==p) //判断指针是否有指向
return -1;
while(p->next!=NULL) //找出尾指针,相当于在遍历链表,但最后指针指向尾指针而不是NULL
{
p=p->next;
} //while(p->next=p->next->next)//可阅读性不好
//类似于while(i=i+1)即while(i++)
Plist q=malloc(sizeof(List)); //开辟一个新的节点用于插入尾部
if(NULL==q) //新节点是否开辟成功
{
perror("malloc");
return -1;
}
q->next=p->next; //新的节点指向p->next(NULL) //q->next=NULL
p->next=q; //原来尾节点的next指向新节点
return 0;
}
(按位置插入)
int insert_pos(Plist p,int pos,int data)
{
if(NULL==p) return -1; //判断合法性
//准备新节点
Plist q=(Plist)malloc(sizeof(List));
if(NULL==p)
return -1;
q->data=data;
q->next=NULL;
//移动
Plist tmp=p; //定义一个指针指向pos-1的位置
while(pos--)
tmp=tmp->next; //将tmp指向了pos-1的节点 //指向了要插入的位置:不算头节点再从0开始
//插入新节点
q->next=tmp->next;
tmp->next=q;
return 0;
}
3.删除节点
int delete_list(Plist p,int pos) //删指定节点
{
if(NULL==p||empty(p))
{
puts("del err");
return -1;
}
while(--pos) // --pos !!!!不是pos--因为删除一个节点,p应该在其上一个节点
{
p=p->next;
}
Plist q=p->next; //定义一个指针记录要删除的节点
p->next=q->next; //p->next=p->next->next
free(q); //释放删除节点的空间
return 0;
}
int delete_data(Plist p, int data) //删指定数据
{
if(NULL == p || empty_list(p))
{
puts("delete arg err");
return -1;
}
//p = p->next; //因为头节点不存数据,所以跳过头节点
while(p->next != NULL)
{
if(p->next->data == data)
{
Plist q = p->next;
p->next = q->next; //p->next = p->next->next;
free(q);
}
else
{
p = p->next;
}
}
}
while(p) //最后p指向NULL
while(p->next) //p指向最后一个节点
while(p->next->next) //p指向倒数第二个节点,常用与清除链表
3.改数据
int change_data(Plist p, int src_data, int dst_data)
{ //源数据 想改为的数据
if(NULL == p)
{
puts("change arg err");
return -1;
}
while(p->next)
{
if(p->next->data == src_data) //判断是否是一个要修改的节点
{
p->next->data = dst_data;
}
p = p->next; //指针向后移动一位,若只改第一个出现的,直接break
}
return 0;
}
4.查数据
int select_list(Plist p,int pos)
{
if(NULL==p||empty(p))
{
puts("select err");
return -1;
}
while(pos--) //pos--!!!在pos的地方停止//删除用的--pos,在pos节点前一个节点停止
{
p=p->next;
}
printf("%d\n",p->data);
return 0;
}
5.show链接
void show(Plist p) //show出链表中所有元素
{
if(NULL == p || empty_list(p)){
return ;
}
p = p->next; //忽略掉头节点未赋值的数据0
while(p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
puts("");
}
6.判断是否为空链表
int empty(Plist p)
{
if(NULL==p) //说明没传入
{
puts("emp err");
return -1;
}
else if(NULL==p->next) // 头节点的next为NULL即空链表
{
return 1;
}
else
{
return 0;
}
}
7.清除链表
Plist clear_list(Plist p)
{
if(NULL==p||empty(p))
{
puts("clear err");
return NULL;
}
Plist q=NULL;
if(!empty(p))
{
while(p->next)
{
q=p->next;
p->next=p->next->next; //p->next=q->next;
free;
}
}
return p;
}
Plist clear_list(Plist p)
{
int len=0;
if(NULL==p||empty(p))
{
puts("clear err");
return NULL;
}
Plist h=p;
while(p->next)
{
p=p->next;
len++;
}
p=h;
while(len--)
{
p=h;
while(p->next->next)
{
p=p->next;
}
Plist q=p->next;
p->next=NULL;
free(q);
}
return p;
}
8.主函数调用
int main(int argc, char *argv[])
{
Plist p=crete_head(); //创建头节点
Plist h=p; //给头节点标志
while(1) //一直输入int型数据,直到输入非数字字符结束
{
int ret=scanf("%d",&data); //ret表示scanf读取成功的个数,非数字就是0
if(0>=ret) //数字字符返回1,非数字返回其他
break;
insert_list(p,data); //确认是数字,插入(头插)节点后
p=p->next;
//节点往后移
//insert_tail(p,data); //尾插,后面就不用加p=p->next了
}
getchar(); //用于吃掉前面输入的非数字字符
p=h;
//p重新指向头节点
show(p); //查看自己创建的链表
puts("please delete data :");
scanf("%d",&pos); //输入删除的节点
delete_list(p,pos);
show(p);
单向循环链表
注意判断条件NULL为phead即可(注意和头节点的比较)
1.创建链表头
Plist creat_head()
{
Plist p=malloc(sizeof(List));
if(NULL==p)
{
perror("create malloc");
return NULL;
}
p->next=p; //循环的链表头
return p;
}
2.尾插
int insert_tail(Plist p)
{
if(NULL==p)
{
puts("head insert arg err");
return -1;
}
Plist phead=p;
while(p->next!=phead) //找到尾节点
p=p->next;
Plist q=malloc(sizeof(List));
if(NULL==q)
{
perror("insert malloc err");
return -1;
}
q->data = data; //数据赋值
q->next = p->next; //q->next = phead;
p->next = q;
return 0;
}
3.删除数据
int delete_data(Plist p, int data)
{
if(NULL == p || empty_list(p))
{
puts("delete arg err");
return -1;
}
Plist phead = p;
while(p->next != phead) //p是头节点,p->next是第一个节点
{
if(p->next->data == data)
{
Plist q = p->next;
p->next = q->next; //p->next = p->next->next;
free(q);
}
else
{
p = p->next;
}
}
return 0;
}
4.修改数据
int change_data(Plist p, int src_data, int dst_data)
{
if(NULL == p)
{
puts("change arg err");
return -1;
}
Plist phead = p;
while(p->next != phead)
{
//判断是否是一个要修改的节点
if(p->next->data == src_data)
{
p->next->data = dst_data;
}
//指针向后移动一位
p = p->next;
}
return 0;
}
5.查找数据
Plist select_data(Plist p, int data)
{
if(NULL == p || empty_list(p))
{
puts("select arg err");
return NULL;
}
Plist phead = p;
while(p->next != phead)
{
if(p->next->data == data){
return p->next;
}
p = p->next;
}
return NULL;
}
6.判断是否为空
int empty_list(Plist p)
{
if(NULL == p){
puts("empty arg err");
return -1;
}
if(p == p->next)
return 1;
else
return 0;
}
7.show
void show(Plist p)
{
if(NULL == p || empty_list(p)){
return ;
}
p = p->next;
while(p != NULL){
printf("%d ", p->data);
p = p->next;
}
puts("");
}
7.清除链表(不去除头节点)
int clear_list(Plist p)
{
if(NULL == p)
{
puts("clear arg err");
return -1;
}
Plist q = NULL, phead = p;
if(!empty_list(p))
{
while(p->next != phead)
{
q = p->next;
p->next = p->next->next; //p->next = q->next;
free(q);
}
}
return 0;
}