考研算法必会|双链表的插入操作、双链表的删除操作

1,240 阅读2分钟

这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战

考研算法必会

单链表与双链表

image.png

双链表的插入操作

双链表的插入操作,假定存储元素e,节点s,插入操作要注意顺序问题

image.png

image.png

s->next = p->next;    //语句①
p->next->prior = s;  //语句②
s->prior=p;          //语句③
p->next = s;  //语句④

插入实现的首要解决的问题是赋值顺序问题,假设第 4 步先执行,则 p->next 提前变成了 s,由 于在第 1 步与第 2 步之间都用到了 p->next,最终插入失败。

双链表的删除操作

如果理解了插入操作,那么删除操作就比较简单了。以双链表为例,如下图删除节点 p 流程图所示,如果要删除节点 p,则需要如下步骤:

image.png

p->prior->next = p->next; //如图① 
p->next->prior = p->prior; //如图②
free(p)                   //释放空间,不要漏掉
//删除结点操作
LinkList DeletElem(LinkList &L,int i){
	int length;
	length=LinkLen(L);
	if(i>0&&i<=length){
		LNode *p,*q;
		p=GetElem(L,i-1);
		q=p->next;
		p->next=q->next;
		free(q);
	}
} 

插入与删除分析

插入操作:

最好情况 T = O(1)

最差情况 T = O(N)

平均情况 T = O(N)

删除操作: 最好情况 T = O(1)

最差情况 T = O(N)

平均情况 T = O(N)

逆置

方法一:头插法

算法思想: 修改指针即可,head 指针遍历链表不断向前移动,用 p 记录 head 的之前的 一个节点,修改各个节点指针域 next,指向 p,用一个 temp 指针指向(保存)head 的 下一个节点。

方法二:递归

递归的方式与迭代的不同之处是,递归是从链表的尾部进行处理的,遍历链表,记录末尾节 点,用 newhead 记录,作为新链表的头节点,工作指针 head 递归返回时,将 head 赋给 head->next->next,并将head->next 置为 NULL。

#include "stdio.h"

struct ListNode
{
    int m_nData;
    ListNode* m_pNext;
};

// pPrev    pNode    pNext
// 正常实现
ListNode* ReverseList(ListNode *pHead)
{
    ListNode* pNode = pHead;
    ListNode* pReversedHead = NULL;
    ListNode* pPrev = NULL;
    while(NULL != pNode)
    {
        ListNode* pNext = pNode->m_pNext;// 保存当前节点的下一个节点
        if (NULL == pNext)
            pReversedHead = pNode;// 如果下一节点为NULL,则当前节点为反转后的头节点,记录

        pNode->m_pNext = pPrev;// 将当前节点的下一个节点指向已经记录的前一个节点,因为要反转嘛
        pPrev = pNode;// 现在要向右错位了,前一个节点成为了当前节点
        pNode = pNext;// 当前节点成为了当前节点的下一个节点
    }
    return pReversedHead;
}
// 递归实现
ListNode* ReverseSingle(ListNode* pNode, ListNode* pPrev)
{
    if (NULL == pNode)
    {
        return pPrev;
    }

    ListNode* pNext = pNode->m_pNext;// 保存当前节点的下一个节点
    pNode->m_pNext = pPrev;

    return ReverseSingle(pNext, pNode);
}

ListNode* ReverseListRecursive(ListNode *pHead)
{
    ListNode* pNode = pHead;
    ListNode* pPrev = NULL;

    return ReverseSingle(pNode, pPrev);
}

int _tmain(int argc, _TCHAR* argv[])
{
    int len = 10;
    ListNode *pHead = new ListNode;
    pHead->m_nData = 10;
    pHead->m_pNext = NULL;
    ListNode *pPrev = pHead;

    for (int i=0; i<len; i++)
    {
        ListNode *p = new ListNode;
        p->m_nData = i; 
        p->m_pNext = NULL;
        if (NULL != pPrev)
        {
            pPrev->m_pNext = p;
        }
        pPrev = p;
    }

    //ListNode *pReversedHead = ReverseList(pHead);
    ListNode* pReversedHead = ReverseListRecursive(pHead);

    return 0;
}