解题思路
我们知道链表有带头指针和不带头指针两种,这个题目的坑在于你最开始选择哪种方式决定了你是走向正确还是失败。在设计之前最好看清各函数的输入、输出,由于插入和删除操作都返回为空,而我们都知道C语言中的函数传惨是按值传递,也就是说,如果你选择不带头指针方式,是没法在在头部进行插入和删除操作的,你尽可以改变函数内的头指针位置,但是主调函数中的头指针位置是无法改变的。
还有要注意的是结构体不能声明为ListNode,因为Leetcode中内部已经定义了该变量,因此这里定义结构体为LNode。
1.先区分一下概念:
头结点:
在单链表第一个元素结点之前设置的一个结点,数据域可以不存任何信息,指针域指向单链表第一个元素的结点。对于单链表来说,头结点可有可无,但为了操作方便,一般情况下单链表都具有头结点,后面的分析将会区别一下有头结点和没有头结点的区别。
优点:
减少了单链表添加删除时特殊情况的判断,减少了程序的复杂性,主要是添加和删除在第一个有元素的结点(首元结点)上有区别,如果链表没有头结点,则删除或添加时都得需要判断一次首元结点,有了头结点以后,首元结点实际为链表的第二个结点,使得所有的元素结点的添加删除更具有统一性,举例如下:
代码
typedef struct LNode{
int val;
struct LNode *next;
} MyLinkedList;
/** Initialize your data structure here. */
MyLinkedList* myLinkedListCreate() {
MyLinkedList *temp = (MyLinkedList*)malloc(sizeof(MyLinkedList));
temp->next = NULL;
return temp;
}
/** Get the value of the index-th node in the linked list. If the index is invalid, return -1. */
int myLinkedListGet(MyLinkedList* obj, int index) {
if(!obj) return -1;
MyLinkedList *ptr = obj->next;
for(int i = 0; ptr && i < index; i++) {
ptr = ptr->next;
}
return ptr ? ptr->val : -1;
}
/** Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. */
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
if(!obj) return -1;
MyLinkedList *temp = (MyLinkedList*)malloc(sizeof(MyLinkedList));
temp->val = val;
temp->next = obj->next;
obj->next = temp;
}
/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
if(!obj) return -1;
MyLinkedList *temp = (MyLinkedList*)malloc(sizeof(MyLinkedList));
temp->val = val;
temp->next = NULL;
// 最后一个不为NULL的节点
MyLinkedList *ptr = obj;
while(ptr->next) {
ptr = ptr->next;
}
ptr->next = temp;
}
/** Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. */
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
if(!obj || index < 0) return -1;
MyLinkedList *temp = (MyLinkedList*)malloc(sizeof(MyLinkedList));
temp->val = val;
temp->next = NULL;
// 找到要插入的前一个节点
MyLinkedList *ptr = obj;
for(int i = 0; ptr && i < index; i++) {
ptr = ptr->next;
}
if(ptr) {
temp->next = ptr->next;
ptr->next = temp;
}
}
/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
if(!obj || index < 0) return -1;
// 找到要删除的前一个节点
MyLinkedList *ptr = obj;
for(int i = 0; ptr && i < index; i++) {
ptr = ptr->next;
}
if(ptr && ptr->next) {
ptr->next = ptr->next->next;
}
}
void myLinkedListFree(MyLinkedList* obj) {
if(!obj) return -1;
obj->next = NULL;
}
/**
* 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);
*/