链表——C语言设计单链表

本文介绍了使用C语言设计单链表的方法,包括需求分析、具体代码实现和常见错误总结。通过设置头结点和结构体表示链表节点,实现了获取指定下标元素、在链表中插入和删除节点等功能。在实现过程中强调了处理空指针和非法下标的注意事项。
摘要由CSDN通过智能技术生成

C语言设计单链表

leetcode 设计链表

需求描述

leetcode 设计链表

在这里插入图片描述

初步分析

  1. 使用c语言来实现,结点采用结构体数据结构,结构体中应至少包含指针域和数据域两部分内容,为了方便,增设头结点指向链表第一个结点。
  2. get(index)函数返回下标为index的结点的数据域的值(也就是第index+1个结点),主要难点在于如何判断index是否合法。假设链表长度为length,当index>=length或者index<0,非法。当然可以在设立头结点时,头结点数据域存储链表长度length,以后每进行一次增删操作,length相应改变。另一种思路是:不设立length值,利用指针current寻找第index+1个结点,在寻找过程中可以间接地得出index是否合法,如果指针current在后移的过程中一直移到链表末尾依旧没有找到第index+1个值,意味着index非法。
  3. 第2点的思路同样应用于其他的和index有关的函数。addAtIndex(index,val)等函数。
  4. 在链表最末删除结点,头部插入结点,销毁链表,思路简单,请阅读代码体会。

具体代码

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);
*/

在这里插入图片描述

易犯错误总结

在进行指针后移时,极易犯的错误便是非法使用空指针
例如以下:

  1. 当待删除结点是最后一个节点时,下面代码注释处会企图使用空指针,非法

/** 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;
}

实际上,在编写代码时应充分考虑到各种情况,避免非法使用空指针,而不是依赖编程环境提示错误信息。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值