1、链表介绍
链表不同于顺序表,顺序表底层采用数组作为存储容器,需要分配一块连续且完整的内存空间进行使用,而链表不需要,它通过一个指针来连接各个分散的结点,形成了一个链状的结构,每个结点存放一个元素,以及一个指向下一个结点的指针,通过这样一个一个相连,最后形成了链表。
它不需要申请连续的空间,只需要按顺序连接即可,虽然物理上可能不想邻,但在逻辑上依然是每个元素相邻存放的,这种结构就叫链表(单链表)
链表分为带头结点的链表和不带头结点的链表,戴头结点的链表就是会有一个头结点指向后续的整个链表,但头结点不存放数据。
2、链表实现
带头结点的链表
typedef int E; //定义别名
struct ListNode{
E element; //保存当前元素
struct ListNode * next; //指向下一个结点的指针
};
typedef struct ListNode * Node; //结点指针起别名,可以直接作为表实现
初始化
void initList(Node head){
head->next = NULL; //头结点默认下一个为null
}
int main(){
struct ListNode head; //创建一个新的头结点,头结点不放任何元素,只做连接,连接整个链表
initList(&head); //进行初始化
}
3、链表的插入
图解
假设想要插入第二个
我们可以修改新插入的结点的后继结点(也就是下一个结点)指向,指向原本在这个位置的结点
接下来我们可以将前驱结点(也就是上一个结点)的后继结点指向修改为我们新插入的结点
这样我们就成功插入了一个新的结点,现在新插入的结点到达了原本的第二个位置上
代码实现
/**
* 在链表的指定位置插入元素
* @param head 头结点
* @param element 要插入的元素
* @param index 要插入的位置(从1开始)
* @return 插入成功返回true,否则返回false
*/
bool insertList(Node head, E element, int index) {
if (index < 1) return false; // 如果索引小于1,插入失败,因为头结点不存放元素
while (--index) { // 通过遍历找到要插入位置的前一个结点
head = head->next;
if (head == NULL) return false; // 如果到达链表末尾仍未找到位置,插入失败
}
Node node = static_cast<Node>(malloc(sizeof(struct ListNode))); // 创建一个新结点
if (node == NULL) return false; // 检查内存分配是否成功
node->element = element; // 将要插入的元素赋值给新结点
node->next = head->next; // 将新结点的指针指向后继结点
head->next = node; // 将前一个结点的指针指向新结点
return true;
}
4、链表的删除
图解
如果想删除第二个结点
其实可以将6的前继结点指向6的后继结点
这样,在逻辑上来说,待删除结点其实已经不在链表中了,我们只需要释放掉待删除结点占用的内存空间就行了
代码实现
/**
* 在链表中删除指定位置的节点
* @param head 头结点
* @param index 待删除节点的位置(从1开始)
* @return 删除成功返回true,否则返回false
*/
bool deleteList(Node head, int index) {
if (index < 1) return false; // 如果索引小于1,删除失败
while (--index) { // 通过遍历找到待删除节点的前一个节点
head = head->next;
if (head == NULL) return false; // 如果到达链表末尾仍未找到位置,删除失败
}
if (head->next == NULL) return false; // 如果待删除节点的下一个节点为空,删除失败
Node nodeTmp = head->next; // 保存要删除的节点的指针
head->next = head->next->next; // 将前一个节点指向待删除节点的下一个节点
free(nodeTmp); // 释放待删除节点的内存
return true;
}
5、链表查询元素
代码实现
获取链表指定位置的元素值
/**
* 获取链表指定位置的元素值
* @param head 头结点
* @param index 查找位置(从1开始)
* @return 指向查找位置元素值的指针,如果位置无效或链表为空则返回NULL
*/
E *getList(Node head, int index) {
if (index < 1) return NULL; // 如果索引小于1,返回NULL,表示位置无效
do {
head = head->next;
if (head == NULL) return NULL; // 如果到达链表末尾仍未找到位置,返回NULL
} while (--index);
return &head->element; // 返回指向查找位置元素值的指针
}
查找对应元素的的位置
/**
* 在链表中查找指定元素的位置
* @param head 头结点
* @param element 要查找的元素值
* @return 返回指定元素在链表中的位置(从0开始计数),如果未找到则返回-1
*/
int findList(Node head, E element) {
int i = 0; // 初始化计数器
while (head) {
if (head->element == element) return i; // 如果找到指定元素,返回当前位置
head = head->next; // 移动到下一个节点
i++; // 增加计数器
}
return -1; // 如果未找到指定元素,则返回-1
}