已解答
中等
相关标签
相关企业
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性: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
提示:
0 <= index, val <= 1000- 请不要使用内置的 LinkedList 库。
- 调用
get、addAtHead、addAtTail、addAtIndex和deleteAtIndex的次数不超过2000。
题解:
typedef struct Node {
int val;
struct Node* next;
} Node;
typedef struct {
int size;
Node* next;
} MyLinkedList;
MyLinkedList* myLinkedListCreate() {
MyLinkedList* shead = (MyLinkedList*)malloc(sizeof(MyLinkedList));
shead->size = 0;
shead->next = NULL;
return shead;
}
int myLinkedListGet(MyLinkedList* obj, int index) {
if (obj->size <= index)
{
return -1;
}
int i;
Node* cur;
cur = obj->next;
for (i = 0;i < index;i ++)
{
cur = cur->next;
}
return cur->val;
}
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
Node* new = (Node*)malloc(sizeof(Node));
new->next = obj->next;
new->val = val;
obj->next = new;
obj->size ++;
return;
}
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
if (obj->size == 0)
{
Node* new = (Node*)malloc(sizeof(Node));
new->next = NULL;
new->val = val;
obj->next = new;
obj->size ++;
return;
}
Node* pre = obj->next;
int i;
for (i = 1;i < obj->size;i ++)
{
pre = pre->next;
}
Node* new = (Node*)malloc(sizeof(Node));
new->next = NULL;
new->val = val;
pre->next = new;
obj->size ++;
return;
}
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if (obj->size < index)
{
return;
}
if (index == 0)
{
Node* new = (Node*)malloc(sizeof(Node));
new->next = obj->next;
new->val = val;
obj->next = new;
obj->size ++;
return;
}
Node* pre = obj->next;
int i;
for (i = 1;i < index;i ++)
{
pre = pre->next;
}
Node* new = (Node*)malloc(sizeof(Node));
new->next = pre->next;
new->val = val;
pre->next = new;
obj->size ++;
return;
}
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (obj->size <= index)
{
return;
}
if (index == 0)
{
Node* cur = obj->next;
obj->next = cur->next;
free(cur);
cur = NULL;
obj->size --;
return;
}
Node* pre = obj->next;
int i;
for (i = 1;i < index;i ++)
{
pre = pre->next;
}
Node* cur = pre->next;
pre->next = cur->next;
obj->size --;
free(cur);
cur = NULL;
return;
}
void myLinkedListFree(MyLinkedList* obj) {
int i;
Node* cur;
cur = obj->next;
while (obj->size > 0)
{
cur = obj->next;
obj->next = cur->next;
free(cur);
cur = NULL;
obj->size --;
}
return;
}
/**
* 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);
*/
为什么函数传入是传地址呢。 因为C语言函数传入参数是值传入。因为C语言函数传入参数是值传入。因为C语言函数传入参数是值传入。 传入变量的值,函数内只是得到了这个值,没法修改原来的内容。传入要修改的变量的地址,函数当作传进来一个指针,就可以修改指针所指地址上的值,实现修改传递到函数外。
一开始没用虚拟头节点,写的很难受,而且很多传入参数结点指针obj,没有传出参数,这就导致obj所指的物理空间的那个节点必须时刻是头节点,对于要在头部插入,可能就得插在第二个位置,然后和第一个互换val值,但这太麻烦了,修改为采用虚拟头节点方案: 虚拟头节点的val是size,next是实际头节点,可以采用分别定义的方法,但实际上节点和虚拟头节点是一样的结构。
原题目给的框架里面obj所指的物理位置不可改变,所以obj就适合作为虚拟头节点。
使用free(cur)后,为了防止cur变成野指针,要补充一句:cur = NULL
写完后有一处bug:
虽然是void不需要返回值,但也要养成写return;的习惯,有一个函数内我分类讨论了:
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if (obj->size <= index)
{
return;
}
if (index == 0)
{
Node* cur = obj->next;
obj->next = cur->next;
free(cur);
cur = NULL;
obj->size --;
return;//-----------例如这里如果忘记return,会继续跑后面的,造成出错--------------
}
Node* pre = obj->next;
int i;
for (i = 1;i < index;i ++)
{
pre = pre->next;
}
Node* cur = pre->next;
pre->next = cur->next;
obj->size --;
free(cur);
cur = NULL;
}