数据结构------移除链表元素

//思路一:遍历原链表,将值为val的节点释放,用三个指针存放
//千万注意:不能访问空指针的next
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
    ListNode* prev,*pcur,*nex;
    prev=head;
    //这样写while循环才能保证把链表开头中全为val的节点弄掉
    while(prev&&prev->val==val)//这两个条件的判断顺序不能变
    {
     //  free(prev);//不能释放了空间再赋值
        prev = prev -> next;
    }
    head=prev;
    //判断去了开头的等于val的节点之后链表是否为空
    if(prev)
    {
        pcur=head->next;
        nex=pcur;
    }
    else
    {
        return head;
    }
    //链表不为空时去除中间的是val的节点
    while(pcur)
    {
        if(pcur->val!=val)
        {
            pcur=pcur->next;
            prev=prev->next;
            nex=nex->next;
        }
        else
        {
            prev->next=nex->next;
            pcur=nex->next;
            // free(nex);
            nex=pcur;
        }
    }
    return head;   
}
//注意:多个指针可以指向同一块空间,只需要改变指针指向就可以了


//思路二:创建新链表
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head,int val)
{
    //创建一个空链表
    ListNode* newHead,*newTail;
    newHead=newTail=NULL;
    //遍历原链表
    ListNode* pcur=head;
    while(pcur)
    {
        //找值不为val的节点,尾插到新链表中
        if(pcur->val!=val)
        {
            if(newHead==NULL)//链表为空
            {
                newHead=newTail=pcur;
            }
            else//链表不为空
            {
                newTail->next=pcur;
                newTail=newTail->next;//尾部指针不断后移
            }
        }
        pcur=pcur->next;
    }
    if(newTail)//若初始链表不为空
        newTail->next=NULL;
    return newHead;//若初始链表为空直接返回也可以
};


//思路三:快慢指针
struct ListNode* removeElements(struct ListNode* head, int val) 
{
    //审题:val是一开始就定的数,而不是你想当然的数组下标!!!
    //删除掉第一位的
    while(head!=NULL && head->val==val){
        head=head->next;
    }
    //第一位不会被删除的
    struct ListNode* cur=head;
    struct ListNode* s = NULL;
    //错误代码示范:此句类型错误,while(cur!=NULL && head->val!=val){   
    while(cur!=NULL){
        //快慢指针
        s = cur->next;
        while(s!=NULL && s->val == val){
            cur->next = cur->next->next;
            free(s);
            s=cur->next;
        }
        cur = cur->next;
    }
    return head;
}


//思路四:递归
struct ListNode* removeElements(struct ListNode* head, int val){ 
    if (NULL == head) {
        return head;
    }     

    /* 删除头节点后所有值为 val 的节点 */
    struct ListNode* res = removeElements(head->next, val);

    /* 头节点是待删除的节点 */
    if (head->val == val) {
        return res;
    /* 头节点不是待删除的节点,头节点后面挂接已处理的链表(更短的) */
    } else {
        head->next = res;
        return head;
    }
}
//化简版:
struct ListNode* removeElements(struct ListNode* head, int val){ 
    if (NULL == head) {
        return head;
    }     

    head->next = removeElements(head->next, val);
    return head->val == val ? head->next : head;
}


//思路五:迭代
struct ListNode* removeElements(struct ListNode* head, int val){
    while (NULL != head && head->val == val) {
        head = head->next;
    }
//链表中全是val的这种情况
    if (NULL == head) {
        return head;
    }

    struct ListNode* pre = head;
    while (pre->next != NULL) {
        /* 找到值为 val 的节点,并将其删除 */
        if (pre->next->val == val) {
            pre->next = pre->next->next;   
        } else {
            /* 没找到,则继续遍历查找 */
            pre = pre->next;
        }
    }
    return head;
}


//思路六:虚拟头节点(哨兵)
struct ListNode* removeElements(struct ListNode* head, int val){
    struct ListNode* dummyHead = (struct ListNode*)malloc(sizeof(struct ListNode));
    if (NULL == dummyHead) {
        return NULL;
    }

    dummyHead->next = head;
    struct ListNode* cur = dummyHead;
    while (cur->next != NULL) {
        if (cur->next->val == val) {
            ListNode* delNode = cur->next;//这个地方注意要创建一个新指针
            cur->next = delNode->next;
            free(delNode);
        } else {
            cur = cur->next;
        }
    }
//注意返回的是第一个真正的节点,而不是虚拟节点
    struct ListNode* retNode = dummyHead->next;
    free(dummyHead);
    return retNode;
}

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值