线性表之双向链表的建立、查找、插入和删除(附C++程序)



一、双链表的基本概念

1.定义:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
在这里插入图片描述
2.特点

**优点:**对于任意的节点,都可以很轻松的获取前节点和后节点。
**缺点:**每个节点都需要保存next和prior两个属性,因此需要更多的空间开销,同时节点的插入和删除也会更费时间,因为需要更多的指向操作。

二、双链表的算法

2.1 双链表的结构定义

双链表节点类型DLinkList的声明如下:

typedef struct DLinkList
{
	ElemType data;                    // 存储链表数据
	struct DLinkList *prior;     		// 指向前驱节点
	struct DLinkList *next;     		// 指向后继节点
}DLinkList;                                  //声明双链表的节点类型

如果没有特别说明,假设单链表都是带头节点的单链表。

2.2 双链表的算法

2.2.1 建立双链表的算法

1. 采用头插法建立双链表

该方法从一个空链表开始,读取数组a中的元素,生成新的节点,将读取的数据存储到新节点的数据域中,然后将新节点插入到当前的链表的表头上,直到结束为止。算法如下:

void CreateDListF(DLinkList *&L, ElemType  a[], int n)
{
    DLinkList *s;
    int i;
    L=(DLinkList *)malloc(sizeof(DLinkList ));     //创建头节点
    L->next=L->prior=NULL;
    for(int i=0;i<n;i++)
    {
        s = (DLinkedlist *)malloc(sizeof(DLinkedlist ));
        s->data = a[i];
        s->next = L->next;               //s指向下一个 
        if ( L->next!=NULL)
        {
                L->next->prior=s;
        }      
        L->next = s;                //再将s给单链表L的表头 
        s->prior=L;
    }
}

本算法的时间复杂度是O(n);

2. 采用尾插法建立双链表
该方法是将新节点插到当前链表的表位上,为止必须增加一个尾节点指针r,使其始终指向当前链表的尾节点。

双链表的尾插法:

Status CreateDListR(DLinkList *&L, ElemType  a[], int n)
{
    DLinkedlist  *s, *r;
    int i;
    L=(DLinkList *)malloc(sizeof(DLinkList ));     //创建头节点
    r = L;
    for(i = 1; i< = n; i++)
    { 
        s =(DLinkList *)malloc(sizeof(DLinkList ));  
         s->data = a[i];
        r->next = s;
        s->prior = r;
        r = s;
    }
    r->next = NULL;
}

本算法的时间复杂度是O(n);

2.2.2 链表的基本运算算法

1.按元素值查找算法

在链表L中从头开始查找第一个值域与x相等的节点,若存在这样的节点,则返回其逻辑序号,否则返回0。

int  Finfnode(DLinkList *L, ElemType  x)
{ 
    DLinkList *p = L->next;
    int i=1;
    while(p != NULL && p->data != x)
    {  
        i++;
         p = p->next;
    } 
    if (p==NULL)   return 0;              //未找到时返回0;
    else return i;                       //找到时,返回序号
}

本算法的时间复杂度是O(n);

2.插入节点操作
假设在双链表中p所指的结点之后插入一个结点s,其操作语句描述为:

s->next = p->next;
s->next->prior = s;
s->prior = p;
p->next = s;

指针变化过程如图:
在这里插入图片描述
算法如下:

//在单链表的第i个元素之前插入元素x
int InsElem(DLinkedlist *&L, ElemType x, int i)
{
	int j=0;
	DLinkedlist *p = L, *s;
	while(p!=NULL && j<i-1)  //查找第i-1个结点*p
	{         
		j++;
		p = p->next;
	}
	if(p == NULL)  return 0;        //未找到结点返回0
	else
	{
		s = (DLinkedlist *)malloc(sizeof(DLinkedlist ));   //创建新结点
		s->data = x;                          //存放元素x
		s->next = p->next;                    //s指向i的元素位置,即p->next的指向
		if (p->next != NULL)   p->next->prior=s;
		s->prior=p;
		p->next = s;                          //插入s后,那么p指向s
		return 1;                             //成功返回1
	}
}

本算法的时间复杂度是O(n);

3.删除节点的操作
设要删除双链表中p结点的后继结点,其操作的语句为:

q= p->next;
p->next= q->next;
q->next->prior= p;
free(q);

指针变化过程如图所示:
在这里插入图片描述
算法如下:

int DelElem((DLinkedlist *&L, ElemType x, int i)
{
	int j=0;
	DLinkedlist *p = L, *q;                //q是要被删除的元素
	if(i<=0)  return 0;
	while(p!=NULL && j<i-1)
	{         //查找第i-1个结点*p
		j++;
		p = p->next;
	}
	if(p == NULL)  return 0;        //未找到结点返回0
	else{
		 q = p->next;
		if(q == NULL)  return 0;
		p->next = q->next;     //i-1指针指向i的指针
		if (p->next != NULL)   p->next->prior=p
		free(q);               //释放q
		return 1;              //成功返回1
		}			
	}
}

本算法的时间复杂度是O(n);

[上一篇]:数据结构之单链表的建立、删除、查找、插入、删除和归并(合并)
[下一篇]:数据结构之循环链表的建立、查找、插入和删除(附C++程序)

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值