单链表的基础知识总结

1.简介

  单链表中的每个结点不仅包含值,还包含链接到下一个结点的引用字段。通过这种方式,单链表将所有结点按顺序组织起来。
在这里插入图片描述

结点结构

// Definition for singly-linked list.
struct SinglyListNode {
    int val;
    SinglyListNode *next;
    SinglyListNode(int x) : val(x), next(NULL) {}
};

操作
在这里插入图片描述

2.添加操作

在这里插入图片描述
示例
在这里插入图片描述

在开头添加结点
在这里插入图片描述

3.删除操作

在这里插入图片描述
示例
在这里插入图片描述

删除第一个结点
在这里插入图片描述

4.设计链表

在这里插入图片描述
在这里插入图片描述

方法1:单向链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码

C

//宏定义,用来返回两个参数中的较大值
#define MAX(a, b) ((a) > (b) ? (a) : (b))

//定义了一个名为 MyLinkedList 的结构体,包含一个指向链表头部的指针 head 
//和一个整型成员变量 size,用来记录链表的节点个数。
typedef struct {
    struct ListNode *head;
    int size;
} MyLinkedList;

//创建链表节点的函数,返回一个指向新节点的指针。函数接受一个整型参数 val,
//用来初始化节点的 val 值为 val,next 指针初始化为 NULL。
struct ListNode *ListNodeCreat(int val) {
    struct ListNode * node = (struct ListNode *)malloc(sizeof(struct ListNode));
    node->val = val;
    node->next = NULL;
    return node;
}

//创建链表的函数,返回一个指向新链表的指针。函数内部先分配一个 MyLinkedList 结构体的空间,
//将其 head 指针初始化为指向一个 val 为 0 的新节点,size 初始化为 0,然后返回该链表的指针。
MyLinkedList* myLinkedListCreate() {
    MyLinkedList * obj = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    obj->head = ListNodeCreat(0);
    obj->size = 0;
    return obj;
}

//这是获取链表指定位置节点值的函数,接受一个指向链表的指针 obj 和一个整型参数 index,
//返回链表中 index 位置节点的 val 值。如果 index 不合法(小于 0 或大于等于链表的节点数),
//则返回 -1。函数内部先将 cur 指针指向链表头部,然后遍历链表,将 cur 指针依次指向链表中 index 位置的节点,
//最后返回该节点的 val 值。
int myLinkedListGet(MyLinkedList* obj, int index) {
    if (index < 0 || index >= obj->size) {
        return -1;
    }
    struct ListNode *cur = obj->head;
    for (int i = 0; i <= index; i++) {
        cur = cur->next;
    }
    return cur->val;
}

//这是在链表指定位置添加节点的函数,接受一个指向链表的指针 obj、一个整型参数 index
//(表示要在哪个位置插入节点)和一个整型参数 val(表示新节点的 val 值)。
//如果 index 大于链表节点数,则不插入节点;否则将 index 限制在 [0, size] 范围内,
//然后将该链表的 size 加 1。接着,遍历链表,找到待插入节点的前一个节点 pred,
//并在其后面插入一个新节点 toAdd,将 toAdd 的 next 指针指向 pred 的 next 指向的节点,
//再将 pred 的 next 指针指向 toAdd。
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    if (index > obj->size) {
        return;
    }
    index = MAX(0, index);
    obj->size++;
    struct ListNode *pred = obj->head;
    for (int i = 0; i < index; i++) {
        pred = pred->next;
    }
    struct ListNode *toAdd = ListNodeCreat(val);
    toAdd->next = pred->next;
    pred->next = toAdd;
}

//这是在链表头部插入节点的函数,实际上是调用 myLinkedListAddAtIndex 函数,
//在 index 为 0 的位置插入一个新节点。
void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    myLinkedListAddAtIndex(obj, 0, val);
}

//这是在链表尾部插入节点的函数,实际上是调用 myLinkedListAddAtIndex 函数,
//在 index 为 size 的位置插入一个新节点。
void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    myLinkedListAddAtIndex(obj, obj->size, val);
}


//这是删除链表指定位置节点的函数,接受一个指向链表的指针 obj 和
//一个整型参数 index(表示要删除哪个位置的节点)。如果 index 不合法,
//则直接返回。否则将该链表的 size 减 1,然后遍历链表,找到待删除节点的前一个节点 pred,
//将 pred 的 next 指针指向待删除节点的下一个节点,最后释放待删除节点的空间。
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if (index < 0 || index >= obj->size) {
        return;
    }
    obj->size--;
    struct ListNode *pred = obj->head;
    for (int i = 0; i < index; i++) {
        pred = pred->next;
    }
    struct ListNode *p = pred->next;
    pred->next = pred->next->next;
    free(p);
}

//这是释放链表空间的函数,接受一个指向链表的指针 obj。函数内部先定义两个指针 cur 和 tmp,
//将 cur 指向链表头部。然后在循环中,将 tmp 指向 cur,将 cur 指向下一个节点,
//最后释放 tmp 指向的节点空间。循环结束后,释放链表头部节点的空间,最后释放链表的空间。
void myLinkedListFree(MyLinkedList* obj) {
    struct ListNode *cur = NULL, *tmp = NULL;
    for (cur = obj->head; cur;) {
        tmp = cur;
        cur = cur->next;
        free(tmp);
    }
    free(obj);
}

C++

class MyLinkedList {
public:
    MyLinkedList() {
        this->size = 0;
        this->head = new ListNode(0);
    }
    
    int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        ListNode *cur = head;
        for (int i = 0; i <= index; i++) {
            cur = cur->next;
        }
        return cur->val;
    }
    
    void addAtHead(int val) {
        addAtIndex(0, val);
    }
    
    void addAtTail(int val) {
        addAtIndex(size, val);
    }
    
    void addAtIndex(int index, int val) {
        if (index > size) {
            return;
        }
        index = max(0, index);
        size++;
        ListNode *pred = head;
        for (int i = 0; i < index; i++) {
            pred = pred->next;
        }
        ListNode *toAdd = new ListNode(val);
        toAdd->next = pred->next;
        pred->next = toAdd;
    }
    
    void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        size--;
        ListNode *pred = head;
        for (int i = 0; i < index; i++) {
            pred = pred->next;
        }
        ListNode *p = pred->next;
        pred->next = pred->next->next;
        delete p;
    }
private:
    int size;
    ListNode *head;
};

方法2:双向链表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
C

#define MAX(a, b) ((a) > (b) ? (a) : (b))

//这个结构体表示双向链表中的一个节点。val 表示节点的值,
//prev 和 next 分别表示指向前一个节点和后一个节点的指针。
typedef struct DLinkListNode {
    int val;
    struct DLinkListNode *prev, *next;
} DLinkListNode;

//这个结构体表示整个双向链表。head 和 tail 分别表示链表的头节点和尾节点,size 表示链表的长度。
typedef struct {
    struct DLinkListNode *head, *tail;
    int size;
} MyLinkedList;


//这个函数用于创建一个新的双向链表节点,并返回该节点的指针。
//在创建节点时,会为节点分配内存空间,并初始化节点的值和指针。
DLinkListNode *dLinkListNodeCreat(int val) {
    DLinkListNode * node = (DLinkListNode *)malloc(sizeof(struct DLinkListNode));
    node->val = val;
    node->prev = NULL;
    node->next = NULL;
    return node;
}

//这个函数用于创建一个新的双向链表,并返回该链表的指针。
//在创建链表时,会为链表分配内存空间,并初始化链表的头节点和尾节点。
//头节点和尾节点的值都为 0,头节点的下一个节点指向尾节点,尾节点的前一个节点指向头节点
MyLinkedList* myLinkedListCreate() {
    MyLinkedList * obj = (MyLinkedList *)malloc(sizeof(MyLinkedList));
    obj->size = 0;
    obj->head = dLinkListNodeCreat(0);
    obj->tail = dLinkListNodeCreat(0);
    obj->head->next = obj->tail;
    obj->tail->prev = obj->head; 
    return obj;
}

//这个函数用于获取双向链表中指定位置的节点的值。如果指定位置超出了链表的范围,则返回 -1。
//在获取节点的值时,需要根据节点的位置判断是从头节点开始还是从尾节点开始遍历。
int myLinkedListGet(MyLinkedList* obj, int index) {
    if (index < 0 || index >= obj->size) {
        return -1;
    }
    DLinkListNode *curr;
    if (index + 1 < obj->size - index) {
        curr = obj->head;
        for (int i = 0; i <= index; i++) {
            curr = curr->next;
        }
    } else {
        curr = obj->tail;
        for (int i = 0; i < obj->size - index; i++) {
            curr = curr->prev;
        }
    }
    return curr->val;
}

//这个函数用于在双向链表的指定位置插入一个新节点。如果插入位置超出了链表的范围,
//则不进行任何操作。如果插入位置为 0,则表示在链表头部插入新节点;如果插入位置为链表长度,
//则表示在链表尾部插入新节点。在插入节点时,需要根据节点的位置判断是从头节点开始还是从尾节点开始遍历。
void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    if (index > obj->size) {
        return;
    }
    index = MAX(0, index);
    DLinkListNode *pred, *succ;
    if (index < obj->size - index) {
        pred = obj->head;
        for (int i = 0; i < index; i++) {
            pred = pred->next;
        }
        succ = pred->next;
    } else {
        succ = obj->tail;
        for (int i = 0; i < obj->size - index; i++) {
            succ = succ->prev;
        }
        pred = succ->prev;
    }
    obj->size++;
    DLinkListNode *toAdd = dLinkListNodeCreat(val);
    toAdd->prev = pred;
    toAdd->next = succ;
    pred->next = toAdd;
    succ->prev = toAdd;
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    myLinkedListAddAtIndex(obj, 0, val);
}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    myLinkedListAddAtIndex(obj, obj->size, val);
}

//这个函数用于删除双向链表中指定位置的节点。如果指定位置超出了链表的范围,
//则不进行任何操作。在删除节点时,需要根据节点的位置判断是从头节点开始还是从尾节点开始遍历。
void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    if (index < 0 || index >= obj->size) {
        return;
    }
    DLinkListNode *pred, *succ;
    if (index < obj->size - index) {
        pred = obj->head;
        for (int i = 0; i < index; i++) {
            pred = pred->next;
        }
        succ = pred->next->next;
    } else {
        succ = obj->tail;
        for (int i = 0; i < obj->size - index - 1; i++) {
            succ = succ->prev;
        }
        pred = succ->prev->prev;
    }
    obj->size--;
    DLinkListNode *p = pred->next;
    pred->next = succ;
    succ->prev = pred;
    free(p);
}


//这个函数用于释放双向链表的内存空间。在释放内存时,需要先释放每个节点的内存空间,再释放链表的内存空间。
void myLinkedListFree(MyLinkedList* obj) {
    struct DLinkListNode *cur = NULL, *tmp = NULL;
    for (cur = obj->head; cur;) {
        tmp = cur;
        cur = cur->next;
        free(tmp);
    }
    free(obj);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值