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
的节点。
示例:
输入
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
输出
[null, null, null, null, 2, null, 3]
解释
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2); // 链表变为 1->2->3
myLinkedList.get(1); // 返回 2
myLinkedList.deleteAtIndex(1); // 现在,链表变为 1->3
myLinkedList.get(1); // 返回 3
考点:
- 获取链表第index的节点值
- 链表的第一个元素前插入新节点
- 链表尾部插入新节点
- 链表的第index个节点前插入新节点
- 删除链表index节点
解法:
单链表–虚拟头节点:
#include <stdlib.h>
// 设置链表节点
typedef struct Node {
int val; // 节点数据
struct Node* next; // 下一个节点指针
} Node;
// 定义链表结构
typedef struct {
int size; // 链表的大小
Node* head; // 链表的头节点(虚拟头节点)
} MyLinkedList;
// 初始化链表
MyLinkedList* myLinkedListCreate() {
MyLinkedList* obj = (MyLinkedList*)malloc(sizeof(MyLinkedList)); // 创建链表对象
obj->size = 0; // 初始化链表大小为0
obj->head = (Node*)malloc(sizeof(Node)); // 创建虚拟头节点
obj->head->next = NULL; // 设置虚拟头节点的next指针为NULL
return obj; // 返回链表对象
}
// 获取链表第index的节点值
int myLinkedListGet(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) { // 检查index是否有效
return -1; // 索引越界
}
Node* current = obj->head->next; // 从第一个有效节点开始
for (int i = 0; i < index; i++) {
current = current->next; // 向后遍历到目标节点
}
return current->val; // 返回节点的值
}
// 在链表的头部添加新节点
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
Node* node = (Node*)malloc(sizeof(Node)); // 为新节点分配内存
node->val = val; // 设置新节点的值
node->next = obj->head->next; // 将新节点的next指向原来第一个节点
obj->head->next = node; // 头节点的next指向新节点
obj->size++; // 链表大小增加
}
// 在链表的尾部添加新节点
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
Node* node = (Node*)malloc(sizeof(Node)); // 为新节点分配内存
node->val = val; // 设置新节点的值
node->next = NULL; // 新节点的next为NULL
Node* current = obj->head; // 从虚拟头节点开始遍历
while (current->next != NULL) { // 遍历到链表的最后一个节点
current = current->next;
}
current->next = node; // 将最后一个节点的next指向新节点
obj->size++; // 链表大小增加
}
// 在链表的第index个节点前插入新节点
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if (index < 0 || index > obj->size) { // 索引非法,返回
return;
}
Node* node = (Node*)malloc(sizeof(Node)); // 为新节点分配内存
node->val = val; // 设置新节点的值
Node* current = obj->head; // 从虚拟头节点开始遍历
for (int i = 0; i < index; i++) {
current = current->next; // 找到第index-1个节点
}
node->next = current->next; // 新节点的next指向当前节点的next
current->next = node; // 当前节点的next指向新节点
obj->size++; // 链表大小增加
}
// 删除链表的第index个节点
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (index < 0 || index >= obj->size) { // 索引非法,返回
return;
}
Node* current = obj->head; // 从虚拟头节点开始遍历
for (int i = 0; i < index; i++) {
current = current->next; // 找到第index-1个节点
}
Node* toDelete = current->next; // 获取要删除的节点
current->next = current->next->next; // 当前节点的next指向要删除节点的next
free(toDelete); // 释放要删除的节点
obj->size--; // 链表大小减少
}
// 释放链表内存
void myLinkedListFree(MyLinkedList* obj) {
Node* current = obj->head;
while (current != NULL) { // 遍历链表
Node* temp = current;
current = current->next;
free(temp); // 释放每个节点
}
free(obj); // 释放链表对象
}
/**
* Your MyLinkedList struct will be instantiated and called as such:
* MyLinkedList* obj = myLinkedListCreate();
* int param_1 = myLinkedListGet(obj, index);
* myLinkedListAddAtHead(obj, val);
* myLinkedListAddAtTail(obj, val);
* myLinkedListAddAtIndex(obj, index, val);
* myLinkedListDeleteAtIndex(obj, index);
* myLinkedListFree(obj);
*/