C语言设计单链表
leetcode 设计链表
需求描述
初步分析
- 使用c语言来实现,结点采用结构体数据结构,结构体中应至少包含指针域和数据域两部分内容,为了方便,增设头结点指向链表第一个结点。
- get(index)函数返回下标为index的结点的数据域的值(也就是第index+1个结点),主要难点在于如何判断index是否合法。假设链表长度为length,当index>=length或者index<0,非法。当然可以在设立头结点时,头结点数据域存储链表长度length,以后每进行一次增删操作,length相应改变。另一种思路是:不设立length值,利用指针current寻找第index+1个结点,在寻找过程中可以间接地得出index是否合法,如果指针current在后移的过程中一直移到链表末尾依旧没有找到第index+1个值,意味着index非法。
- 第2点的思路同样应用于其他的和index有关的函数。addAtIndex(index,val)等函数。
- 在链表最末删除结点,头部插入结点,销毁链表,思路简单,请阅读代码体会。
具体代码
typedef struct MyLinkedList{
int val;
struct MyLinkedList * next;
} MyLinkedList;
/** Initialize your data structure here. */
MyLinkedList* myLinkedListCreate() {
MyLinkedList* L = (MyLinkedList*) malloc(sizeof(MyLinkedList));
L->next = NULL;
return L;
}
/** 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(index<0){
return -1;
}
MyLinkedList* current = obj->next;
for(int i = 0;i<index;i++){
if(!current)
return -1;
current = current->next;
}
if(!current){
return -1;
}
else
return current->val;
}
/** 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) {
MyLinkedList* newNode = (MyLinkedList*) malloc(sizeof(MyLinkedList));
newNode->next = obj->next;
obj->next = newNode;
newNode->val = val;
}
/** Append a node of value val to the last element of the linked list. */
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
MyLinkedList* p = obj;
while(p->next){
p = p->next;
}
MyLinkedList* newNode = (MyLinkedList*) malloc(sizeof(MyLinkedList));
p->next = newNode;
newNode->next = NULL;
newNode->val = val;
}
/** 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(index <= 0)
return myLinkedListAddAtHead(obj, val) ;
MyLinkedList* current = obj;
MyLinkedList* newNode = (MyLinkedList*) malloc(sizeof(MyLinkedList));
newNode->val = val;
for(int i = 0;i<index;i++){
if(!current){
free(newNode);
return;
}
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
}
/** Delete the index-th node in the linked list,
if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
MyLinkedList* current = obj;
for(int i = 0;i<index;i++){
if(!current)
return;
current = current->next;
}
MyLinkedList* delNode = current->next;
if(!delNode){
current->next = NULL;
}
else
current->next = delNode->next;
free(delNode);
}
void myLinkedListFree(MyLinkedList* obj) {
MyLinkedList* current = obj->next;
MyLinkedList* currentNext = NULL;
while(current){
currentNext = current->next;
free(current);
current = currentNext;
}
obj = 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);
*/
易犯错误总结
在进行指针后移时,极易犯的错误便是非法使用空指针。
例如以下:
- 当待删除结点是最后一个节点时,下面代码注释处会企图使用空指针,非法
/** Delete the index-th node in the linked list, if the index is valid. */
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
MyLinkedList* current = obj;
for(int i = 0;i<index;i++){
if(!current)
return;
current = current->next;
}
MyLinkedList* delNode = current->next;
current->next = delNode->next;
//当待删除结点是最后一个节点时,此处会企图使用空指针,非法
free(delNode);
}
判断current是否为空即可进行改进即可。
改进后:
//改进后
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
MyLinkedList* current = obj;
for(int i = 0;i<index;i++){
if(!current)
return;
current = current->next;
}
MyLinkedList* delNode = current->next;
if(!delNode){
current->next = NULL;
}
else
current->next = delNode->next;
free(delNode);
}
2.又例如
/** 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(index<0){
return -1;
}
MyLinkedList* current = obj->next;
for(int i = 0;i<index;i++){
if(!current)
return -1;
current = current->next;
//此处可能出现非法使用空指针的情况。
//例如链表里只含一个节点,index = 1 时,
//最终退出循环时current = NULL;
}
return current->val;
}
根据题目要求,index非法返回-1。
改进后:
//改进后
/** 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(index<0){
return -1;
}
MyLinkedList* current = obj->next;
for(int i = 0;i<index;i++){
if(!current)
return -1;
current = current->next;
//此处可能出现非法使用空指针的情况。
//例如链表里只含一个节点,index = 1 时,
//最终退出循环时current = NULL;
}
if(!current){
return -1;
}
else
return current->val;
}
实际上,在编写代码时应充分考虑到各种情况,避免非法使用空指针,而不是依赖编程环境提示错误信息。