1、实现链表需要用结构体定义一个类型
struct Student
{
int id;
char name[128];
Student* next;
}
结构体中的成员类型可以是自己,next的类型是Student,而不是Student。所有的指针类型本质上是一个整数,4字节,所以包含一个整数是没有问题的
Student ss[4]
{
{201901,"Join",0};
{201902,"Jennifer",0};
{201903,"AnXi",0};
}
①为什么name类型是char,赋值时用的双引号
②成员next初始化为0
2、无头链表:所有节点都包含有效数据;有头链表:头节点本身不包含有效数据
3、程序实现链表(一个节点中可能包含多条数据)
①定义有头链表
Student m_head={0,"head",NULL};
结构体名 自定义头节点名称 结构体元素初试为空(成员next初试为NULL)
从上面可以发现一个节点中包含多条数据
②向链表中插入元素
先创建需要插入的对象(创建对象时用到malloc函数),然后调用节点插入函数
Student* obj=(Student*)malloc(sizeof(Student));
obj->id=12;
strcpy(obj->name,"X");
add(obj)
定义add函数将节点加入到最前面
void add(Student* obj)
{
obj->next=m_head.next;
m_head.nex=obj;
}
m_head.next中的next是结构体中的元素,用于指向下一个对象,所以取出元素的过程就相当于是定义了一个新的指针
对象是用->,结构体使用 .
m_head.next表示指向下一个元素?
定义add函数将节点加入到最后面
void add(obj)
{
Student* p=&m_head;
while(p->next)
{
p=p->next;
}
p->next=obj;
obj->next=NULL;
}
遍历链表是必须加上第一句:定义一个新的指针,用于遍历元素
③有头链表的遍历
有头链表的头节点不含数据,是不参与遍历的,主需要访问链表中的数据节点:通过定义一个指针实现
void show_all()
{
Student* p=m_head.next;//避开链表头
while(p)
{
printf("id:%d,name:%s",p->id,p->name);
p=p->next;
}
}
链表头之后才是头节点,注意区分链表头和头节点
④中间某一位置插入节点(按数据大小将节点出入到合适的位置)
void add(*obj)
{
Student* cur=m_head.next;
Student* pre=&m_head;
while(obj->id>cur->id)
{
pre=cur;
cur=cur->next;//此处是cur->next,不是cur.next,从结构体中取出元素
}
obj->next=cur;
pre->next=obj;
return 0;
}
书本143面给出的答案和自己写的区别:
while(cur)
{
if(obj->id<cur->id)
break;
pre=cur;
cur=cur->next;//此处是cur->next,不是cur.next,从结构体中取出元素
}
obj->next=pre->next;
pre->next=obj;
通过if条件跳出循环
自己用cur代替了pre->next
⑤查找、删除节点
通过输入的id与遍历到的id是否相等来判断是否删除节点
对链表头进行操作用&(&m_head),对头节点进行操作(m_head.next)
void remove(int id)
{
Student* pre=&m_head;
Student* cur=m_head.next;
while(cur)
{
if(id==cur->id)
{
pre->next=cur->next;
free(cur)
break;
}
pre=cur;//这句一定是在下一句的上面
cur=cur->next;
}
}
链表长度统计
一个链表的节点定义为
struct Node
{
int data;
Node* next;
};
实现一个函数int GetLength (Node* lst);其中,lst为有头链表的头节点, 返回值为链表的数据节点的个数。
struct Node
{
int data;
Node* next;
};
int GetLength (Node* lst)
{
int count = 0; // 数据节点的个数
Node* p = lst->next;
while(p)
{
count += 1;
p = p->next;
}
return count;
}