首页 > 其他分享 >双向链表

双向链表

时间:2024-04-29 20:35:35浏览次数:15  
标签:tmp DoubleLList return Head next 链表 双向 NULL

双向链表接口设计

// 指的是双向链表中的结点有效数据类型,用户可以根据需要进行修改
typedef int DataType_t;
// 构造双向链表的结点,链表中所有结点的数据类型应该是相同的
typedef struct DoubleLinkedList
{
	DataType_t data;			   // 结点的数据域
	struct DoubleLinkedList *prev; // 直接前驱的指针域
	struct DoubleLinkedList *next; // 直接后继的指针域
} DoubleLList_t;
 

DoubleLList_t *DoubleLList_Create()
{
	// 1.创建一个头结点并对头结点申请内存
	DoubleLList_t *Head = (DoubleLList_t *)calloc(1, sizeof(DoubleLList_t));
	if (NULL == Head)
	{
		perror("Calloc memory for Head is Failed");
		exit(-1);
	}
	// 2.对头结点进行初始化,头结点是不存储数据域,指针域指向NULL
	Head->prev = NULL;
	Head->next = NULL;
	// 3.把头结点的地址返回即可
	return Head;
}
 
DoubleLList_t *DoubleLList_NewNode(DataType_t data)
{
	// 1.创建一个新结点并对新结点申请内存
	DoubleLList_t *New = (DoubleLList_t *)calloc(1, sizeof(DoubleLList_t));
	if (NULL == New)
	{
		perror("Calloc memory for NewNode is Failed");
		return NULL;
	}
	// 2.对新结点的数据域和指针域(2个)进行初始化
	New->data = data;
	New->prev = NULL;
	New->next = NULL;
	return New;
}

//头插
bool DoubleLList_HeadInsert(DoubleLList_t *Head, DataType_t data)
{
	DoubleLList_t *new = DoubleLList_NewNode(data);
	DoubleLList_t *tmp = Head->next;
	if (Head->next == NULL) // empty list 链表为空的情况
	{
		Head->next = new;
		return true;
	}
	new->next = Head->next; // normal situation 普通情况
	Head->next->prev = new;
	Head->next = new;
	return true;
}

//尾插
bool DoubleLList_TailInsert(DoubleLList_t *Head, DataType_t data)
{
	DoubleLList_t *new = DoubleLList_NewNode(data);
	DoubleLList_t *tmp = Head->next;
	if (Head->next == NULL) // judge is the null 链表为空的情况
	{
		Head->next = new;
		return true;
	}
	while (tmp->next != NULL) // as the normal situation,find the last node 普通情况,遍历寻找最后的节点
		tmp = tmp->next;
	tmp->next = new; // 在尾部插入节点
	new->prev = tmp;
	return true;
}
 
//中间插
bool DoubleLList_DestInsert(DoubleLList_t *Head, DataType_t destval, DataType_t data)
{
	DoubleLList_t *tmp = Head->next;
	DataType_t i = Head->data;
	if (Head->next == NULL) // judge the empty list 链表为空的情况
	{
		printf("The list is empty,there is no destival.\n");
		return false;
	}
	DoubleLList_t *new = DoubleLList_NewNode(data);
	while (destval != tmp->data && tmp->next != NULL)
	// as the normal situation,find the destval找到目标值
	{
		tmp = tmp->next;
	}
	if (destval == tmp->data) // 如果存在目标值,则进行插入操作
	{
		new->next = tmp->next;
		tmp->next->prev = new;
		new->prev = tmp;
		tmp->next = new;
		return true;
	}
	else // 如果不存在目标值,则插入无效,直接返回
	{
		printf("There is no destval\n");
		return false;
	}
}

//头删
bool DoubleLList_HeadDel(DoubleLList_t *Head)
{
	// 对链表的首结点的地址进行备份
	DoubleLList_t *Phead = Head->next;
	// DoubleLList_t *tmp = Head->next;
	if (Head->next == NULL) // 判断当前链表是否为空,为空则直接退出
	{
		printf("current linkeflist is empty!\n");
		return false;
	}
	Head->next = Phead->next; // delete the head 直接进行删除首节点操作
	Phead->next = NULL;
	Phead->prev = NULL;
	Head->next->prev = NULL;
	free(Phead);
	return true;
}

//尾删
bool DoubleLList_TailDel(DoubleLList_t *Head)
{
	DoubleLList_t *tmp = Head->next;
	if (Head->next == NULL) // 判断当前链表是否为空,为空则直接退出
	{
		printf("current linkeflist is empty!\n");
		return false;
	}
	while (tmp->next != NULL) // find the last node 普通情况,遍历寻找最后的节点
	{
		tmp = tmp->next;
	}
	tmp->prev->next = NULL; // 此处应考虑,是否需要增加一个变量记录目标值直接前驱
	tmp->prev = NULL;
	tmp->next = NULL;
	free(tmp);
	return true;
}

//中间删
bool DoubleLList_MidDel(DoubleLList_t *Head, DataType_t destval)
{
	DoubleLList_t *tmp = Head->next;
	if (Head->next == NULL) // 判断当前链表是否为空,为空则直接退出
	{
		printf("current linkeflist is empty!\n");
		return false;
	}
	while (tmp->data != destval && tmp->next != NULL) // find the specific node找到指定值的节点
	{
		tmp = tmp->next;
	}
	if (tmp->data == destval && tmp == Head->next)
	{
		Head->next = tmp->next; // 如果存在目标值,且目标值位于首节点时,进行头删操作
		Head->next->prev = NULL;
		tmp->next = NULL;
		tmp->prev = NULL;
		free(tmp);
		return true;
	}
	else if (tmp->data == destval) // 如果存在目标值,且目标值不位于首节点时,进行删除操作
	{
		tmp->prev->next = tmp->next;
		tmp->next->prev = tmp->prev;
		tmp->prev = NULL;
		tmp->next = NULL;
		free(tmp);
		return true;
	}
	else // 如果不存在目标值,则直接返回
	{
		printf("The is no destival\n");
		return false;
	}
}

//遍历
bool DoubleLList_Print(DoubleLList_t *Head)
{
	// 对链表头结点的地址进行备份
	DoubleLList_t *Phead = Head;
	// 判断当前链表是否为空,为空则直接退出
	if (Head->next == Head)
	{
		printf("current linkeflist is empty!\n");
		return false;
	}
	// 从首结点开始遍历
	while (Phead->next)
	{
		// 把头结点的直接后继作为新的头结点
		Phead = Phead->next;
		// 输出头结点的直接后继的数据域
		printf("data = %d  ", Phead->data);
		// 判断是否到达尾结点,尾结点的next指针是指向首结点的地址
		if (Phead->next == Head->next)
		{
			break;
		}
	}
	return true;
}

//测试
int main(int argc, char const *argv[])
{
	DoubleLList_t *H = DoubleLList_Create();
	DoubleLList_HeadInsert(H, 20);
	DoubleLList_HeadInsert(H, 30);
	DoubleLList_TailInsert(H, 40);
	DoubleLList_TailInsert(H, 20);
	DoubleLList_TailInsert(H, 50);
	DoubleLList_DestInsert(H, 30, 31);
	DoubleLList_DestInsert(H, 32, 31);
 
	DoubleLList_Print(H);
	puts("");
	DoubleLList_HeadDel(H);
	DoubleLList_TailDel(H);
	DoubleLList_MidDel(H, 31);
 
	DoubleLList_Print(H);
	puts("");
	return 0;
}

标签:tmp,DoubleLList,return,Head,next,链表,双向,NULL
From: https://www.cnblogs.com/CamelliaWY/p/18166599

相关文章

  • 在vue2中,什么是双向绑定,为什么vue3要进行优化?
    一、什么是双向绑定我们先从单向绑定切入单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定举个栗子 当用户填写表单时,View......
  • 双向循环链表队列的接口设计
    /***************************************************filename:DoubleLinkQueue.c*author:[email protected]*date:2024/04/28*brief:构建双向循环链队的接口*note:None**CopyRight(c)[email protected]......
  • 链表
    P1996约瑟夫问题动态链表临时分配链表节点,使用完毕后释放链表节点。优点:能及时释放空间,不使用多余内存缺点:需要管理空间,容易出错。#include<bits/stdc++.h>#defineintlonglong#definerep(i,a,b)for(inti=(a);i<=(b);++i)#definefep(i,a,b)for(int......
  • 适合保险行业的双向同步方案应该是怎么样的?
    对于很多金融机构而言,基于国家政策要求及数据安全考虑,都会建立异地数据中心,保险机构也不例外,保险机构的数据中心是一种集中存储、处理和管理数据的设施,由一系列硬件和软件组成,包括服务器、存储设备、网络设备等,以提供一个高效、安全和可靠的环境来处理和存储大量数据。其主要功能......
  • 双向循环链表接口设计
    /***************************************************filename:DoubleDoubleCirLkList.c*author:[email protected]*date:2024/04/25*brief:通过构建双向循环链表学习顺序存储*note:None**CopyRight(c)2024momolyl@126......
  • 链表逆序
    编写一个函数,实现单链表逆序,,函数原型如下:*voidreverse_list(single_listhead)程序代码如下:voidreverse_list(single_list*head){single_list*p=head->next;//将链表除头节点的节点保存head->next=NULL;//将链表断开single_list*tmp=NULL;while(......
  • 单向循环链表接口设计
    目录单向循环链表接口设计创建新的头结点创建新节点并初始化该节点工具函数遍历链表查找尾结点查找尾结点前置驱动找到指定结点查找指定节点前置驱动创建每一个新节点并插入到头部新建结点并插入到尾部新建结点并插入到指定节点之后删除头部结点删除尾部结点删除指定结点调试函数......
  • 双向循环链表的头插法的实现
    include<stdio.h>include<stdlib.h>typedefstructslik{intdata;structslik*next;structslik*prev;}sli;voidcreatesli(sli**head,inta[],intsize){for(inti=0;i<size;i++){sli*s=(sli*)malloc(sizeof(sli));s->data=a[i];......
  • 单向循环链表的头插法实现
    ``#include<stdio.h>``````include<stdlib.h>typedefstructslik{intdata;structslik*next;}sli;voidcreatesli(sli**head,inta[],intsize){for(inti=0;i<size;i++){sli*s=(sli*)malloc(sizeof(sli));s->data=a[i];s->......
  • 单向循环链表的尾插法实现
    `#include<stdio.h>include<stdlib.h>typedefstructslik{intdata;structslik*next;}sli;voidcreatesli(sli**head,inta[],intsize){for(inti=0;i<size;i++){sli*s=(sli*)malloc(sizeof(sli));s->data=a[i];s->next=NU......