【数据结构】双链表解析+完整代码(创建、插入、删除)

3.2 双链表

3.2.1 双链表的定义
  • 定义

    单链表的缺点:无法逆向操作,插入删除时只能从头开始遍历,很不方便。

    双链表:每个结点都定义两个指针prior和next,分别指向前驱和后继,可进可退。

typedef struct DNode{
    ElemType data;
    struct DNode *prior,*next; //前驱指针和后继指针
}DNode,*DLinklist;
  • 初始化双链表

    bool InitDLinkList(DLinklist &L){
        L=(DNode*)malloc(sizeof(DNode)); //分配头结点
        if(L==NULL)return false;
        L->prior=NULL; //头结点的前驱指针永远指向NULL
        L->next=NULL; //头结点还暂时没有后继
    }
    
  • 判空(带头结点)

    bool Empty(DLinkList L){
        if(L->next==NULL)
            return true;
        else
            return false;
    }
    
3.2.2 双链表的插入
  • 步骤

    如图

    1.要插入结点s连接p的后继结点:s->next=p->next;

    2.p的后继结点连接s:p->next->prior=s;

    3.要插入结点s与p连接:s->prior=p;

    4.p与s连接:p->next=s;

    • 注:语句顺序不唯一,但不任意。

bool InsertNextDNode(DNode*p,DNode*s){
    if(p==NULL||s=NULL)return false;
    
    s->next=p->next;
    if(p->next!=NULL)p->next->prior=s; //先判断p有没有后继结点,防止p为链尾结点时产生的空指针
    s->prior=p;
    p->next=s;
    return true;
}
  • 时间复杂度: O ( 1 ) O(1) O(1)
3.2.3 双链表的删除
  • 步骤

    如图:

    1.将p指向要删结点q的后继结点:p->next=q->next

    2.将q的后继结点与p连接:q->next->prior=p

    3.释放要删结点q:free(q)

    • 时间复杂度: O ( 1 ) O(1) O(1)
//删除结点p的后继结点
bool DeleteNextDNode(DNode *p){
    if(p==NULL)return false;
    DNode *q=p->next; //q为要删结点
    if(q==NULL)return false;
    p->next=q->next;
    if(q->next!=NULL)q->next->prior=p; //该判断防止q是最后一个结点,从而指针制空
    free(q);
    return true;
}
  • 销毁双链表

    void DestoryList(DLinklist &L){
        //循环释放各结点数据
        while(L->next!=NULL)
            DeleteNextNode(L);
        free(L); //释放头结点
        L=NULL; //头指针指向NULL
    }
    
*完整代码 双链表

以上只解释了双链表的定义、插入、删除,其他查找等操作与单链表一样,可看文章:
【数据结构】单链表解析+完整代码(创建 增删 查找等)
这里不再赘述,只在代码中展现。

#include<stdio.h>
#include<stdlib.h>

#define ElemType int

typedef struct DNode {
	ElemType data;
	struct DNode* prior,*next;
}DNode, * DLinkList;

//初始化
bool InitList(DLinkList& L) {
	L = (DNode*)malloc(sizeof(DNode));
	L->next = NULL;
	L->prior = NULL;
	return true;
}

//求表长
int Length(DLinkList L) {
	int len = 0;
	DNode* p = L;
	while (p->next != NULL) {
		len++;
		p = p->next;
	}
	return len;
}

//头插法建立
DLinkList List_HeadInsert(DLinkList& L) {
	L = (DNode*)malloc(sizeof(DNode));
	L->next = NULL;
	DNode* s;
	int x;
	scanf("%d", &x);
	while (x != 9999) {
		s = (DNode*)malloc(sizeof(DNode));
		s->data = x;
		s->next = L->next;
		L->next = s;
		scanf("%d", &x);
	}
	return L;
}

//尾插法建立
DLinkList List_TailInsert(DLinkList& L) {
	int x;
	L = (DNode*)malloc(sizeof(DNode)); //创建头结点
	DNode* s, * r = L; //s指向头结点,r指向尾结点
	scanf("%d", &x);
	while (x != 9999) {
		s = (DNode*)malloc(sizeof(DNode));
		s->data = x;
		r->next = s;
		r = s;
		scanf("%d", &x);
	}
	r->next = NULL;
	return L;
}

//按序查找
DNode* GetItem(DLinkList& L, int i) {
	DNode* p = L->next;
	int j = 0;
	while (j < i && p != NULL) {
		p = p->next;
		j++;
	}
	return p;
}

//按值查找
int LocateElem(DLinkList& L, ElemType e) {
	DNode* p = L;
	int j = 0;
	while (p != NULL && p->data != e) {
		p = p->next;
		j++;
	}
	return j;
}

//按位序插入
bool ListInsert(DLinkList& L, int i, ElemType e) {
	if (i < 0)return false;

	DNode* p = L;
	int j = 0;
	while (j < i - 1 && p != NULL) {
		p = p->next;
		j++;
	}
	if (p == NULL)return false;

	DNode* s = (DNode*)malloc(sizeof(DNode));
	s->data = e;
	s->next = p->next;
	p->next = s;
	return true;
}

//指定结点后插操作
bool InsertNextDNode(DNode* p, DNode* s) {
	if (p == NULL||s==NULL)return false;

	s->next = p->next;
	if (p->next != NULL)p->next->prior = s; //先判断p有没有后继结点,防止p为链尾结点时产生的空指针
	s->prior = p;
	p->next = s;
	return true;
}

//删除结点p的后继结点
bool DeleteNextDNode(DNode* p) {
	if (p == NULL)return false;
	DNode* q = p->next; //q为要删结点
	if (q == NULL)return false;
	p->next = q->next;
	if (q->next != NULL)q->next->prior = p; //该判断防止q是最后一个结点,从而指针制空
	free(q);
	return true;
}

void PrintList(DLinkList& L) {
	DNode* p = L->next;
	while (p != NULL) {
		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n\n");
}

void DestroyList(DLinkList& L) {
	//循环释放各结点数据
	while (L->next != NULL)
		DeleteNextDNode(L);
	free(L); //释放头结点
	L = NULL; //头指针指向NULL
}

int main() {
	DLinkList L;

	printf("头插法建立链表,输入以9999结束:\n");
	L = List_HeadInsert(L);
	PrintList(L);

	DestroyList(L);
	printf("尾插法建立链表,输入以9999结束:\n");
	L = List_TailInsert(L);
	PrintList(L);

	printf("求表长:%d\n", Length(L));
	printf("\n");

	printf("按位序插入:\n");
	int pos = 1, e = 998;
	ListInsert(L, pos, e);
	PrintList(L);

	printf("指定结点的后插操作:\n");
	DNode* p = L->next;
	DNode* q=(DNode*)malloc(sizeof(DNode));
	q->data = 222;
	q->next = NULL;
	q->prior = NULL;
	InsertNextDNode(p, q);
	PrintList(L);

	printf("按值查找:\n");
	printf("查找222的位序是:%d\n", LocateElem(L, 222));
	printf("\n");

	printf("按序查找:\n");
	DNode*x = GetItem(L, 2);
	printf("查找第3个元素值是:%d\n", x->data);
	printf("\n");

	printf("按指定结点删除:\n");
	p = L->next;
	DeleteNextDNode(p);
	PrintList(L);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值