单链表相关操作详解

关于单链表的一些操作

1.删除一个节点:

若给定了被删除节点之前的节点,则可以改变前节点的指向,并释放后节点即可
代码实现:

struct listnode * delect(struct listnode * head)
{
    struct listnode * use = head -> next ;
    head -> next = head -> next -> next ;
    free(use);
    return head;
}

若值给定了被删除节点,则无法改变前节点的指向,同时也无法移动后节点的地址,但是我们可以将后节点的内容拷贝并覆盖在当前节点上在释放后节点,达到删除节点的效果。
代码实现:

  void * delect(struct listnode * det)
  {
     struct listnode * temp = det -> next; 
     *(det) = *(det -> next) ;//将后节点的内容复制并覆盖
     free(temp);
     return ;
  }

2.寻找中间节点

运用快慢指针的方法,快指针一次走两步,慢指针一次走一步,直到快指针走到尾节点时停止,此时慢指针指向的就是链表的中间位置。
运用此方法也可以寻找三分之一点,四分之一点等,但是要注意边界条件和不能越界。
代码实现:

   struct listnode * mid(struct listnode * head)
   {
       struct listnode * fast = head;
       struct listnode * slow = head;
       while(fast != NULL && fast -> next != NULL) //确保一次走两步不越界
        {
            fast = fast -> next -> next;
            slow = slow -> next ;
        }
        return slow ;
   }  

3.反转一个单链表

可以运用递归的方法,利用系统堆栈暂时存储各节点的地址并依次反转
代码实现:

    struct listnode * reverse(struct listnode * head)
    {
        if(head == NULL || head -> next == NULL)
            {
                return head;
            }
        struct listnode * newhead = reverse(head -> next);
        head -> next -> next = head;
        head -> next =  NULL;
        return newhead;
    }

也可以使用头删加头插法,对原链表进行头删,对新链表进行头插即可。
代码实现:

    struct listnode * reverse(struct listnode * head)
    {
        struct listnode * newhead = NULL;
        struct listnode * node ;
        while(head != NULL)
            {
                node = head ; //暂时存储被头删的节点
                head = head -> next;//原链表头删
                node -> next = newhead;//新链表头插
                newhead = node;//更新链表头
            }
        return newhead;
    }

当然也可以使用三个指针依次改变链表的指向。
代码实现:

    struct listnode * reverse(struct listnode * head)
    {
        struct listnode * cur = head ;
        struct listnode * pre = null;
        struct listnode * then = head ;
        while(cur != null)
        {
            then = cur -> next;
            cur -> next = pre;
            pre = cur ;
            cur = then;
        }
        return pre;
    }

4.归并两个有序链表:

利用归并排序的思想,不过与归并排序不同的是,链表的归并并不需要复制出一个等长的链表,只需要一个新的头节点即可。
代码实现:

struct listnode * merge(struct listnode * head1,struct listnode * head2)
{
    struct listnode * newhead = (struct listnode *)(malloc(sizeof(struct listnode))) ;
    struct listnode * ret = newhead;
    newhead -> val = 0;
    newhead -> next = null;
    while(head1 != NULL && head2 != NULL)
    {
        if(head1 -> val < head2 -> val)
            {
                newhead -> next = head1;
                head1 = head1 -> next;
            }
        else
            {
                newhead -> next = head2;
                head2 = head2 -> next;
            }
        newhead = newhead -> next ;
    }
    while(head1 != NULL)
    {
        newhead -> next = head1;
        head1 = head1 -> next ;
        newhead = newhead -> next;
    }
    while(head2 != NULL)
    {
        newhead -> next = head2;
        head2 = head2 -> next ;
        newhead = newhead -> next;
    }
    return (ret -> next) ; //排除新增的头节点
}

> 更复杂的操作均可以使用以上的基础操作组合实现,比如实现链表的排序就可以使用归并排序的思想 :

 struct ListNode * merge(struct ListNode * head1,struct ListNode * head2)
{
    struct ListNode * ret = (struct ListNode * )(malloc(sizeof(struct ListNode))) ;
    struct ListNode * use = ret ;
    struct ListNode * p1 = head1 ;
    struct ListNode * p2 = head2 ;
    while(p1 != NULL && p2 != NULL)
    {
        if( p1 -> val <= p2 -> val)
        {
            use -> next = p1;
            p1 = p1 -> next;
        }
        else
        {
            use -> next = p2;
            p2 = p2 -> next;
        }
        use = use -> next;
    }
    while(p1 != NULL)
    {
        use -> next = p1;
        p1 = p1 -> next;
        use = use -> next;
    }
    while(p2 != NULL)
    {
        use -> next = p2;
        p2 = p2 -> next;
        use = use -> next;
    }
    return (ret->next);
}

struct ListNode * mergesort(struct ListNode * head,struct ListNode * end)
{
    if(head == NULL)
        return head;
    if(head -> next == end)
    {
        head -> next = NULL;
        return head;
    }
    struct ListNode * fast = head;
    struct ListNode * slow = head;
    while(fast != end && fast -> next != end)  
    {
        fast = fast -> next -> next;
        slow = slow -> next;
    }
    return merge(mergesort(head,slow),mergesort(slow,end));
}

在递归处理时务必关注边界条件和入参的改变,比如在mergesort()函数中寻找中点时就需要改变判断条件,不然会报错

> 判断回文链表,就可以通过寻找中点+链表逆置+遍历判断

代码实现:
   bool isPalindrome(struct ListNode* head){
struct ListNode * fast = head -> next;
struct ListNode * slow = head;
struct ListNode * newhead = NULL;
bool ret = true;
//if(slow == NULL || fast == NULL)
//    return true;    此处特殊情况被包括进了下面的一般循环判断之中
while(fast != NULL && fast -> next != NULL)
    {
        slow = slow -> next;
        fast = fast -> next -> next;
    }
newhead = reverse(slow -> next) ;
while(ret && newhead  != NULL)  //当只要有一个为假时,立即跳出循环,并设 //置返回值  
// 此处通过分析可以发现只要确保第二段链表的尾节点不为空,那么第一段的节点也不会为空
    {
        if(head -> val != newhead -> val)
            ret = false ;
        head = head -> next;
        newhead = newhead -> next;
    }
return ret;


}

> 在环形链表中操作时也可以通过先截断再操作最后再相连来简化一定的逻辑

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单链表是一种线性表,它由一系列结点组成,每个结点包含数据域和指针域。数据域存储数据,指针域指向下一个结点。 单链表的实现原理如下: 1.定义结点结构体 定义一个结点结构体,包含数据域和指针域。 ``` struct ListNode{ int val; struct ListNode *next; }; ``` 2.创建链表 创建链表需要定义一个头结点,头结点不存储任何数据,只是为了方便操作。 定义头结点: ``` struct ListNode *head = NULL; ``` 3.插入结点 插入结点需要遍历链表找到插入位置,然后将新结点插入到链表中。 插入结点的代码: ``` struct ListNode* insertNode(struct ListNode* head, int val) { struct ListNode *p = head; struct ListNode *newNode = (struct ListNode*)malloc(sizeof(struct ListNode)); newNode->val = val; newNode->next = NULL; if (p == NULL) { head = newNode; } else { while (p->next != NULL) { p = p->next; } p->next = newNode; } return head; } ``` 4.删除结点 删除结点需要遍历链表找到要删除的结点,然后将其从链表中删除。 删除结点的代码: ``` struct ListNode* deleteNode(struct ListNode* head, int val) { struct ListNode *p = head; struct ListNode *prev = NULL; if (p == NULL) { return head; } while (p != NULL && p->val != val) { prev = p; p = p->next; } if (p == NULL) { return head; } if (prev == NULL) { head = head->next; } else { prev->next = p->next; } free(p); return head; } ``` 5.查找结点 查找结点需要遍历链表找到要查找的结点。 查找结点的代码: ``` struct ListNode* searchNode(struct ListNode* head, int val) { struct ListNode *p = head; while (p != NULL && p->val != val) { p = p->next; } return p; } ``` 6.遍历链表 遍历链表需要从头结点开始,依次访问每个结点。 遍历链表的代码: ``` void traverseList(struct ListNode* head) { struct ListNode *p = head; while (p != NULL) { printf("%d ", p->val); p = p->next; } } ``` 以上就是单链表的实现原理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值