代码随想录算法训练营第3天| 链表理论基础 、203.移除链表元素 、707.设计链表、 206.反转链表

顺序
1.先自己敲代码发现不会
2.看思路题解,不要看具体代码
3.再敲,看能不能通过,找问题
4.发现还是不想,对比看具体代码

链表理论基础

链表的存储方式

了解完链表的类型,再来说一说链表在内存中的存储方式。

数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。

链表是通过指针域的指针链接在内存中各个节点。

所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。

链表的定义

这里我给出C/C++的定义链表节点方式,如下所示:

struct ListNode {
    int val;  // 节点上存储的元素
    ListNode *next;  // 指向下一个节点的指针
    ListNode(int x) : val(x), next(NULL) {}  // 节点的构造函数
};

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

C/C++最后要自己释放结点内存空间

链表的释放

在这里插入图片描述

移除链表元素

题目链接/文章讲解/视频讲解::https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html

想法

struct ListNode* removeElements(struct ListNode* head, int val){
   struct ListNode *p=head;
   while(head->val==val&&head->next!=NULL&&head!=NULL)
    {   head=head->next;}
    while(p->next!=NULL&&p!=NULL){
        if(p->next->val==val)
        p->next=p->next->next;
        else
        p=p->next;
    }
    return head;

}

错误
1.链表最基础的定义和释放不清楚,复习数据结构
2.逻辑不清,导致出现空指针错误
3.

解法

1.暴力解法

struct ListNode* removeElements(struct ListNode* head, int val){
   struct ListNode *p=head;
   while(head!=NULL&&head->val==val)
    {   head=head->next;}
    while(p!=NULL&&p->next!=NULL){
        if(p->next->val==val)
        p->next=p->next->next;
        else
        p=p->next;
    }
    return head;

}
将头结点为所需元素和之后元素为所需元素的情况分开讨论

2.虚拟头结点法

设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了。

struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* fakehead=(ListNode *)malloc(sizeof(ListNode));
    fakehead->next=head;
    struct ListNode* cur=fakehead;
    while(cur!=NULL&&cur->next!=NULL){
        if(cur->next->val==val)
            cur->next=cur->next->next;
        else cur=cur->next;
    }
    return fakehead->next;

}

707.设计链表

题目链接/文章讲解/视频讲解:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html

想法

typedef struct MyLinkedList{
    int val;
    struct MyLinkedList *next;

} MyLinkedList;


MyLinkedList* myLinkedListCreate() {

}

int myLinkedListGet(MyLinkedList* obj, int index) {
        int result;
        int i;
        for(i=1;obj!=NULL;i++){
            result=obj->val;
            if(i==index)
            return result;
            else obj=obj->next;
        }
        return -1;
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
    struct MyLinkedList *fakehead=malloc(sizeof(struct MyLinkedList));
    fakehead->val=val;
    fakehead->next=obj;
}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
        while(obj!=NULL&&obj->next!=NULL){
            obj=obj->next;
        }
        struct MyLinkedList *addtail=malloc(sizeof(struct MyLinkedList));
        obj->next=addtail;
        addtail->val=val;
        addtail->next=NULL;
}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    int i;
    struct MyLinkedList addindex;
    if(index<0)
    {
        addindex->next=obj;
        addindex->val=val;
    }
    for(i=1;obj!=NULL&&obj->next!=NULL;i++){
        if(i==index-1)
        obj->next=addindex;
        obj->val=val;
        else obj=obj->next;
    }
    if(i==index-1){
        obj->next=addindex;
        addindex->next=NULL;
        addindex->val=val;
    }
}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    int i;
    for(i=1;obj!=NULL;i++){
        if(i=index-1){
            obj->next=obj->next->next;
        }
        obj=obj->next;

    }
}

void myLinkedListFree(MyLinkedList* obj) {

}

错误
1.不清楚链表结构定义,命名,释放,复习数据结构
2.出现空指针问题
3.将头指针直接移动

解法

虚拟头节点法

将头节点为删除或头节点前为插入位置的情况与之后结点为删除或插入位置的情况统一代码

typedef struct MyLinkedList{
    int val;
    struct MyLinkedList* next;

} MyLinkedList;


MyLinkedList* myLinkedListCreate() {
  MyLinkedList* head = (MyLinkedList *)malloc(sizeof (MyLinkedList));
    head->next = NULL;
    return head;
}

int myLinkedListGet(MyLinkedList* obj, int index) {
    if(index<0)
    return -1;

    MyLinkedList* p;//index可以从0开始
    p=obj->next;
    int i;
    for(i=0;p!=NULL;i++){
        if(i==index){
            return p->val;
        }
        else p=p->next;
    }
    
        return -1;

    
}

void myLinkedListAddAtHead(MyLinkedList* obj, int val) {
        MyLinkedList *cur=(MyLinkedList *)malloc(sizeof(MyLinkedList));
        cur->val=val;
        cur->next=obj->next;
        obj->next=cur;

}

void myLinkedListAddAtTail(MyLinkedList* obj, int val) {
    int i;
    MyLinkedList *cur;
    cur=obj;
    MyLinkedList *Add=(MyLinkedList *)malloc(sizeof(MyLinkedList));
    Add->val=val;
    Add->next=NULL;
    for(i=0;cur->next!=NULL;i++){
        cur=cur->next;
    }
    cur->next=Add;
    

}

void myLinkedListAddAtIndex(MyLinkedList* obj, int index, int val) {
    int i;
    MyLinkedList *p=(MyLinkedList *)malloc(sizeof(MyLinkedList));
    p->val=val;
    MyLinkedList *cur=obj;
    for(i=0;cur!=NULL;i++){
        if(i==index){
            p->next=cur->next;
            cur->next=p;
        }
        else cur=cur->next;
    }

}

void myLinkedListDeleteAtIndex(MyLinkedList* obj, int index) {
    MyLinkedList *cur=obj;
    int i;
    for(i=0;cur->next!=NULL;i++){
        if(i==index){
            cur->next=cur->next->next;
        }
        else cur=cur->next;
    }


}

void myLinkedListFree(MyLinkedList* obj) {
        while(obj != NULL){
        MyLinkedList *tmp = obj;
        obj = obj->next;
        free(tmp);

}}

这道题传入的指针是虚拟头结点的指针,开始以为是头结点指针,而且也不能直接移动头节点指针,要根据每个函数的实际情况,新令一个指针指向虚拟头节点或头节点

206.反转链表

题目链接/文章讲解/视频讲解:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html

想法:

用一个新链表接收旧链表传来的数据,然后将其反向连接

struct ListNode* reverseList(struct ListNode* head){
    int i;
    struct ListNode *cur=head;
    for(i=0;cur!=NULL;i++){
        struct ListNode *p=(ListNode *)malloc(sizeof(ListNode));
        p->val=cur->val;
        if(i==0)
        p->next=NULL;
        else p->next=p;
        cur=cur->next;
    }
return p;

}

错误
1.反向连接时,每次循环p都被重新覆盖了,找不到上一个p的位置
2.在循环里定义的元素出循环后会失效

解法

1.双指针法

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

struct ListNode* reverseList(struct ListNode* head){
    struct ListNode *pre=NULL;
    struct ListNode *cru=head;
    struct ListNode *temp=NULL;
    while(cru!=NULL&&head!=NULL){
        temp=head->next;
        head->next=pre;
        pre=head;
        head=temp;
    }
    return pre;
}

注意
1.命名的指针必须首先就赋值,不然会变成野指针不能在后面运用
2.要考虑head本身为空的情况

2.递归法

在这里插入图片描述
将重复的地方和循环改成了递归(有点小难,二刷再做吧)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值