1、链表
1.1、链表的结构
- 每个链表开头都有一个头指针Head
- 尾节点的指针域为NULL,用于判断此列表是否结束
- 如果一个链表开始就为NULL,那么该链表为空链表
- 链表中的先后不代表在真实内存中的位置,只是单纯的逻辑上关系
1.2、创建链表
- 我们首先利用结构体创建一个Student的结构体
//利用链表创建3个学生的信息,学生信息包括姓名和年龄
struct Student
{
char name[20];
int age;
//这里存放的下个节点的地址
Student *next;
};
- 接着我们给我们的节点赋值,跟着上面的图,我们知道需要一个头节点(无数据,只存地址),一个尾节点(有数据,地址为NULL)
Student c = { "t3",21, nullptr};//尾节点,指针域为nullptr
Student b = { "t2",27,&c };
Student a = { "t1",22,&b };
Student* head = &a; //头指针,指向a,无值
1.3、链表数据的遍历
创建完链表后,我们来输出一下内容,那么我们就需要链表a的地址,然后输出完当前内容后,将指针指向下一个地址
//定义一个指针来指向head
Student *pointer = head;
//循环到尾节点(nullptr)时结束
while (pointer)
{
cout << pointer->name << " " << pointer->age << endl;
//输出完后指向下一个
pointer = pointer->next;
}
1.4、链表的查找
- 我们查找一下t2这个人,并返回他的年龄
while (pointer)
{
if (pointer->name=="t2")
{
cout << pointer->age << endl;
break;
}
pointer = pointer->next;
}
if (pointer==nullptr)
{
cout << "没有找到此人" << endl;
}
1.5、链表的插入
我们首先手动新加一条数据
Student d = { "t4",21,nullptr };
区别与数组,我们不需要移动任何数据,只需要将要插入的地方的前一项地址指向插入的数据,插入的数据再指向后一条数据即可(PS:灵魂画手,不要介意)
这里需要注意一点,先指向C,不然早断开C会找不到C的地址,也就是E的指针域要先指向C的地址,防止丢失。
那么我们就在t2的后面插入一条数据
//before指向前一条数据
//pointer指向后一条数据
Student* before = head;
Student *pointer = before->next;
while (before)
{
if (before->name=="t2")
{
d.next = pointer; //赋值&c的地址
before->next = &d; //t2断开c的地址,链接d的地址
break;
}
//如果不匹配,就让俩个指针往后走
before = pointer;
pointer = before->next;
}
1.6、链表的删除
那么删除就只需要将要被删除的节点指向的地址,给到前一个节点。
那我们就删除上面新加的t4
before = head;
pointer = before->next;
//这里需要注意是因为要删除后一个,所以pointer作为循环条件
while (pointer)
{
if (pointer->name == "t4")
{
before->next = pointer->next;
break;
}
before = pointer;
pointer = pointer->next;
}
2、链表和数组的区别
数组 | 链表 | |
---|---|---|
内存占用 | 连续内存 | 灵活,无限制 |
元素类型 | 相同类型 | 可以相同,可以不同 |
组织形式 | 在内存中连续排序 | 各节点在内存中彼此分散,靠指针联系 |
插入删除元素 | 需要遍历 | 只修改某个或几个节点的指针 |