在开始程序之前说一个困扰的几天的东西,在链表做形参的时候什么时候用(**p)什么时候用(*p)
答案:只要是要修改head指针必须传递head的地址(用**p),否则传递head值即可(*p)。这与普通变量类似,当需要修改普通变量的值,需传递其地址,否则传递普通变量的值即可(引用)
详细的解释可以在csdn查到,附上链接:https://bbs.csdn.net/topics/360084495
#include
#include
typedef struct List
{
int data;
struct List *next;
}list,*p_list;
void creat_list(list **p)//如果链表为空,则创建一个链表,指针域指向自己,否则寻找尾节点,将
{ //将尾节点的指针域指向这个新节点,新节点的指针域指向头结点
int item;
list *temp;
list *target;
printf("输入节点的值,输入0结束\n");
while(1)
{
scanf("%d",&item);
if(item==0)return;
if(*p==NULL) //如果输入的链表是空。则创建一个新的节点,使其next指针指向自己 (*head)->next=*head;
{
*p=(list *)malloc(sizeof(list));
if(!*p)exit(0);
(*p)->data=item;
(*p)->next=*p;
}
else //输入的链表不是空的,寻找链表的尾节点,使尾节点的next=新节点。新节点的next指向头节点
{
for(target=*p;target->next!=*p;target=target->next);//寻找尾节点
temp=(list *)malloc(sizeof(list));
if(!temp)exit(0);
temp->data=item;
temp->next=*p; //新节点指向头节点
target->next=temp;//尾节点指向新节点
}
}
}
图片和程序结合起来看
void show(list *p)//遍历,循环链表的遍历最好用do while语句 ,因为头节点就有值
{
list *temp;
temp=p;
do
{
printf("%5d",temp->data);
temp=temp->next;
}
while(temp!=p);
printf("\n");
}
循环链表中最重要的是 头节点和尾节点,多数的操作都需要考虑到尾节点和头节点的特殊处理
代码
void insert(list **pNode,int place,int num) //链表的插入 place位置 num 数据
{
list *temp,*target;
int i;
if(place==1)//如果输入的数字是1,表示要插入头节点。应该特殊处理
{ //首先找到尾节点,让后让新节点的next指向头节点,尾节点指向新的头节点,在让头指针指向temp。这要特别注意
temp=(list *)malloc(sizeof(list));
if(!temp)exit(0);
temp->data=num;
for(target=*pNode;target->next!=*pNode;target=target->next);
temp->next=*pNode;
target->next=temp;
*pNode=temp;/////////特别注意
}
else//在其他的地方插入节点。 同样先找到要插入的位置,如果位置超出链表的长度,自动插入队尾。
{//找到要插入位置的前一个节点target,让target->next=temp,插入节点的前驱指向新节点,新节点指向target->next的地址
for(i=1,target=*pNode;target->next!=*pNode&&i!=place-1;target=target->next,i++);
temp=(list *)malloc(sizeof(list));
temp->data=num;
temp->next=target->next;
target->next=temp;
}
}
结合图片来看看
void Delete(list **pNode,int place) //删除操作
{
list *temp,*target;
int i;
temp=*pNode;
if(temp==NULL) //首先判断链表是否为空
{
printf("这是一个空指针 无法删除\n");
return;
}
if(place==1) //如果删除的是头节点
{ //应当特殊处理,找到尾节点,使尾节点的next指向头节点的下一个节点
// rear->next=(*head)->next;然后让新节点作为头节点,释放原来的头节点
for(target=*pNode;target->next!=*pNode;target=target->next);
temp=*pNode;
*pNode=(*pNode)->next;
target->next=*pNode;
free(temp);
}
else //删除其他节点
{ //首先找出尾节点
for(i=1,target=*pNode;target->next!=*pNode&&i!=place-1;target=target->next,i++);
if(target->next==*pNode) //判断要删除的位置是否大于链表长度,若大于链表长度,
//特殊处理直接删除尾节点
{
//找出尾节的前一个节点
for(target=*pNode;target->next->next!=*pNode;target=target->next);
temp=target->next; // 尾节点的前一个节点直接指向头节点 释放原来的尾节点
target->next=*pNode;
printf("数字太大删除尾巴\n");
free(temp);
}
else
{
temp=target->next;// 删除普通节点 找到要删除节点的前一个节点target,
//使target指向要删除节点的下一个节点 转存删除节点地址
target->next=temp->next; // 然后释放这个节点
free(temp);
}
}
}
看看流程图
int findval(list *pNode,int val) //寻找值 返回位置
{
int i=1; //从一开始,因为头节点也有值
list *node;
node=pNode;
while(node->data!=val&&node->next!=pNode)
{
i++;
node=node->next;
}
if(node->next==pNode&&node->data!=val)//尾节点指向头节点就跳出,因此还要检测一次为节点的data
{
return -1;
}
return i;
}
#include
#include
typedef struct List
{
int data;
struct List *next;
}list,*p_list;
void creat_list(list **p)//如果链表为空,则创建一个链表,指针域指向自己,否则寻找尾节点,将
{ //将尾节点的指针域指向这个新节点,新节点的指针域指向头结点
int item;
list *temp;
list *target;
printf("输入节点的值,输入0结束\n");
while(1)
{
scanf("%d",&item);
if(item==0)return;
if(*p==NULL) //如果输入的链表是空。则创建一个新的节点,使其next指针指向自己 (*head)->next=*head;
{
*p=(list *)malloc(sizeof(list));
if(!*p)exit(0);
(*p)->data=item;
(*p)->next=*p;
}
else //输入的链表不是空的,寻找链表的尾节点,使尾节点的next=新节点。新节点的next指向头节点
{
for(target=*p;target->next!=*p;target=target->next);//寻找尾节点
temp=(list *)malloc(sizeof(list));
if(!temp)exit(0);
temp->data=item;
temp->next=*p; //新节点指向头节点
target->next=temp;//尾节点指向新节点
}
}
}
void insert(list **pNode,int place,int num) //链表的插入
{
list *temp,*target;
int i;
if(place==1) //如果输入的数字是1,表示要插入头节点。应该特殊处理
{ //首先找到尾节点,让后让新节点的next指向头节点,尾节点指向新的头节点,在让头指针指向temp。这要特别注意
temp=(list *)malloc(sizeof(list));
if(!temp)exit(0);
temp->data=num;
for(target=*pNode;target->next!=*pNode;target=target->next);
temp->next=*pNode;
target->next=temp;
*pNode=temp;/////////特别注意
}
else //在其他的地方插入节点。 同样先找到要插入的位置,如果位置超出链表的长度,自动插入队尾。 tar new 原来是2
{ //找到要插入位置的前一个节点target,让target->next=temp,插入节点的前驱指向新节点,新节点指向target->next的地址 1 2 3
for(i=1,target=*pNode;target->next!=*pNode&&i!=place-1;target=target->next,i++);
temp=(list *)malloc(sizeof(list));
temp->data=num;
temp->next=target->next;
target->next=temp;
}
}
void Delete(list **pNode,int place) //删除操作
{
list *temp,*target;
int i;
temp=*pNode;
if(temp==NULL) //首先判断链表是否为空
{
printf("这是一个空指针 无法删除\n");
return;
}
if(place==1) //如果删除的是头节点
{ //应当特殊处理,找到尾节点,使尾节点的next指向头节点的下一个节点 rear->next=(*head)->next;然后让新节点作为头节点,释放原来的头节点
for(target=*pNode;target->next!=*pNode;target=target->next);
temp=*pNode;
*pNode=(*pNode)->next;
target->next=*pNode;
free(temp);
}
else
{ //删除其他节点
for(i=1,target=*pNode;target->next!=*pNode&&i!=place-1;target=target->next,i++); //首先找出尾节点
if(target->next==*pNode) //判断要删除的位置是否大于链表长度,若大于链表长度,特殊处理直接删除尾节点
{
for(target=*pNode;target->next->next!=*pNode;target=target->next);//找出尾节的前一个节点
temp=target->next; // 尾节点的前一个节点直接指向头节点 释放原来的尾节点
target->next=*pNode;
printf("数字太大删除尾巴\n");
free(temp);
}
else
{
temp=target->next;// 删除普通节点 找到要删除节点的前一个节点target,使target指向要删除节点的下一个节点 转存删除节点地址
target->next=temp->next; // 然后释放这个节点
free(temp);
}
}
}
int findval(list *pNode,int val) //寻找值
{
int i=1;
list *node;
node=pNode;
while(node->data!=val&&node->next!=pNode)
{
i++;
node=node->next;
}
if(node->next==pNode&&node->data!=val)//尾节点指向头节点就跳出,因此还要检测一次为节点的data
{
return -1;
}
return i;
}
void show(list *p)//遍历,循环链表的遍历最好用do while语句 ,因为头节点就有值
{
list *temp;
temp=p;
do
{
printf("%5d",temp->data);
temp=temp->next;
}
while(temp!=p);
printf("\n");
}
int main()
{
list *head=NULL;
list *val=NULL;
int place,num;
creat_list(&head);
printf("原始的链表:");
show(head);
printf("输入要删除的位置:");
scanf("%d",&place);
Delete(&head,place);
show(head);
printf("输入要插入的位置和数据用空格隔开:");
scanf("%d %d",&place,&num);
insert(&head,place,num);
show(head);
printf("输入你想查找的值:");
scanf("%d",&num);
place=findval(head,num);
if(place!=-1)printf("找到的值的位置是place=%d\n",place);
else printf("没找到值\n");
return 0;
}