203.移除链表元素
题目链接/文章讲解/视频讲解::代码随想录
题目:给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。
虚拟头节点方法
思路:
添加一个头节点,符合题意断链重连释放内存即可。不要忘记一些边界条件,尾元素指空。
用一个指针用来遍历整个链表,直到该指针为空退出循环
代码
struct ListNode* removeElements(struct ListNode* head, int val) {
// 定义 ListNode 结构
typedef struct ListNode ListNode;
// 分配内存给一个新的 ListNode
ListNode *L = (ListNode*)malloc(sizeof(ListNode));
// 创建指向前一个节点、当前节点和临时节点的指针
ListNode *pre = L;
ListNode *p = head;
ListNode *q;
// 将新的 ListNode 的下一个指针指向链表的头部
L->next = head;
pre->next = head;
// 循环遍历链表
while(p != NULL)
{
// 如果当前节点的值与目标值匹配
if(p->val == val)
{
// 将 q 指向当前节点,将 p 移动到下一个节点,更新前一个节点的下一个指针,释放当前节点
q = p;
p = p->next;
pre->next = p;
free(q);
}
else
{
// 移动到下一个节点并更新前一个节点
p = p->next;
pre = pre->next;
}
}
// 更新链表的头部并释放临时的 ListNode
head = L->next;
free(L);
// 返回更新后的链表头部
return head;
}
不使用虚拟头结点
思路:
若不添加头结点,在释放结点时要判断该结点是否是头结点,若是则单独处理
代码
struct ListNode* removeElements(struct ListNode* head, int val) {
// 定义 ListNode 结构
typedef struct ListNode ListNode;
// 创建指向当前节点和临时节点的指针
ListNode *p = head;
ListNode *q = NULL;
// 如果链表为空,则返回空
if(head==NULL)
return NULL;
// 循环遍历链表
while(p != NULL && p->next != NULL)
{
// 如果下一个节点的值等于目标值
if(p->next->val == val)
{
// 将 q 指向下一个节点,将当前节点的下一个指针指向下一个节点的下一个节点,释放下一个节点
q = p->next;
p->next = p->next->next;
free(q);
}
else
{
// 移动到下一个节点
p = p->next;
}
}
// 如果头部节点的值等于目标值
if(head->val == val)
{
// 将 q 指向头部节点,更新头部节点为下一个节点,释放头部节点
q = head;
head = head->next;
free(q);
}
// 返回更新后的头部节点
return head;
}
707.设计链表
题目链接/文章讲解/视频讲解:代码随想录
题目:你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:
val
和next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。如果是双向链表,则还需要属性
prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。实现
MyLinkedList
类:
MyLinkedList()
初始化MyLinkedList
对象。int get(int index)
获取链表中下标为index
的节点的值。如果下标无效,则返回-1
。void addAtHead(int val)
将一个值为val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为val
的节点插入到链表中下标为index
的节点之前。如果index
等于链表的长度,那么该节点会被追加到链表的末尾。如果index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为index
的节点。
代码讲解
完整代码
typedef struct {
int val; // 节点的值
struct MyLinkedList * next; // 指向下一个节点的指针
} MyLinkedList; // 定义链表结构体
MyLinkedList* myLinkedListCreate() {
MyLinkedList* head = (MyLinkedList*)malloc(sizeof(MyLinkedList)); // 创建链表头节点
head->next = NULL; // 头节点的下一个节点指针为空
return head; // 返回链表头节点
}
int myLinkedListGet(MyLinkedList* obj, int index) {
int i = 0;
MyLinkedList* temp = obj->next; // 从第一个节点开始遍历链表
while(temp!=NULL)
{
if(i == index) // 找到指定位置的节点
{
return temp->val; // 返回节点的值
}
i++;
temp = temp->next; // 继续遍历下一个节点
}
return -1; // 如果未找到指定位置的节点,返回-1
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
MyLinkedList* temp = (MyLinkedList*)malloc(sizeof(MyLinkedList)); // 创建新节点
temp->next = obj->next; // 新节点的下一个节点指向原来的第一个节点
temp->val = val; // 新节点的值为传入的值
obj->next = temp; // 头节点的下一个节点指向新节点
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
MyLinkedList* p = obj;
MyLinkedList* temp = (MyLinkedList*)malloc(sizeof(MyLinkedList)); // 创建新节点
temp->val = val; // 新节点的值为传入的值
temp->next = NULL; // 新节点的下一个节点指针为空
while( (p!=NULL) && (p->next!=NULL) )
{
p = p->next; // 找到链表的最后一个节点
}
p->next = temp; // 将新节点连接到最后一个节点的后面
}
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
MyLinkedList* temp = (MyLinkedList*)malloc(sizeof(MyLinkedList)); // 创建新节点
int count = index;
MyLinkedList* p = obj->next;
MyLinkedList* pre = obj;
temp->val = val; // 新节点的值为传入的值
while(count!=0&&p!=NULL)
{
count--;
p = p->next; // 找到指定位置的节点
pre = pre->next;
}
if(count == 0)
{
pre->next = temp; // 将新节点插入到指定位置
temp->next = p;
}
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
MyLinkedList* temp = (MyLinkedList*)malloc(sizeof(MyLinkedList)); // 创建新节点
int count = index;
MyLinkedList* p = obj->next;
MyLinkedList* pre = obj;
while(count!=0&&p!=NULL)
{
count--;
p = p->next; // 找到指定位置的节点
pre = pre->next;
}
if(count == 0&&p!=NULL)
{
pre->next = p->next; // 将指定位置的节点从链表中删除
free(p); // 释放删除节点的内存空间
}
}
void myLinkedListFree(MyLinkedList* obj) {
while(obj!=NULL)
{
MyLinkedList* temp = obj;
obj = obj->next; // 释放链表中每个节点的内存空间
free(temp);
}
}
206.反转链表
题目链接/文章讲解/视频讲解:代码随想录
给你单链表的头节点
head
,请你反转链表,并返回反转后的链表。
思路:
用尾插法把所有元素重新插入即可
完整代码
// 定义一个指向结点的指针temp,用malloc动态分配内存空间
struct ListNode* temp = (struct ListNode*)malloc(sizeof(struct ListNode));
// 将temp的下一个指针指向NULL
temp->next = NULL;
// 定义一个指向下一个结点的指针pnext
struct ListNode* pnext;
// 如果链表为空,直接返回NULL
if(head==NULL)
return NULL;
// 定义一个指向当前结点的指针p,初始指向头结点
struct ListNode* p = head;
// 遍历链表
while(p!=NULL)
{
// 将p的下一个结点指针赋值给pnext
pnext = p->next;
// 将p的下一个结点指针指向temp的下一个结点指针
p->next = temp->next;
// 将temp的下一个结点指针指向p
temp->next = p;
// 将p指向pnext,即p指向下一个结点
p = pnext;
}
// 将头结点指向temp的下一个结点
head = temp->next;
// 释放temp指向的内存空间
free(temp);
// 返回翻转后的链表头结点
return head;
总结:
灵活运用头插法和尾插法即可,要记得保存前驱后者后继以防断链。