数据结构学习——双向链表

 1、设计链表

//1、设计数据结点
typedef int ElemType_t;
typedef struct node{
	ElemType_t data;//数据域
	struct node *prev;//上一个地址
	struct node *next;//下一个地址
}Node_t;

//设计链表管理结构体---头节点
struct list{
	Node_t *head;	//存储链表的数据首结点
	Node_t *tail;	//存储链表的数据尾结点
	int nodeNumber; //存储结点的数量
};

2、申请结点并初始化

/*
函数功能:申请一个新结点并且初始化,把新节点的地址返回
返回值:
参数:
*/
Node_t *new_node(struct list* listHead,ElemType_t inputData)
{
	//1、申请新结点的内存空间
	Node_t *newNode = malloc(sizeof(Node_t));
	if(newNode == NULL)
	{
		perror("malloc newNode error");
		return NULL;
	}
		//2、初始化
	newNode->data = inputData;
	newNode->prev = NULL;
	newNode->next = NULL;
	
	//结点的数量+1
	listHead->nodeNumber++;
	
	return newNode;
}

3、创建链表

/*
函数功能:创建一条链表
返回值:
参数:
*/
struct list* create_list()
{
	//1、申请链表的头节点的内存空间并且初始化
	struct list *listHead = malloc(sizeof(struct list));
	if(listHead == NULL)
	{
		perror("malloc listHead error\n");
		return NULL;
	}
	listHead->head = NULL;
	listHead->tail = NULL;
	listHead->nodeNumber = 0;
	//2、从键盘上输入数据进行初始化
	printf("请输入数据:");
	while(1)
	{
		ElemType_t inputData;
		int ret = scanf("%d",&inputData);
		if(ret != 1 || inputData == -1)//退出条件
			break;
			
		//1)新建一个结点并且初始化
		Node_t *newNode = new_node(listHead,inputData);
		if(newNode == NULL)
		{
			printf("new_node error\n");
			return NULL;
		}
		//2)如果当前链表是空,那么新建的这一个结点是链表的首结点,同时也是尾结点
		if(listHead->head == NULL)	//从无到有
		{
			listHead->head = newNode;
			listHead->tail = newNode;
		}
		else	//从少到多
		{	//链表的尾结点的next成员指向新结点
			listHead->tail->next = newNode;
			//新结点的prev成员存储,原来链表的尾结点的地址
			newNode->prev = listHead->tail;
			//b更新链表的尾结点
			listHead->tail = newNode;
		}
	}
	//3、返回整条链表的头节点的地址
	return listHead;
}

4、尾插法

/*
函数功能:尾插法
返回值:
参数:
*/
int insert_nodeToList_tail(struct list *listHead,ElemType_t inputData)
{
	//1、判断listHead是否有效
	if(listHead == NULL)
	{
		printf("listHead is NULL,%s error\n",__FUNCTION__);
		return -1;
	}
	//2、新建结点并且初始化
	Node_t*newNode = new_node(listHead,inputData);
	if(newNode == NULL)
	{
		printf("new_node error\n");
		return -1;
	}
	//如果当前链表没有数据结点,那么新建的这一个结点是链表的首结点也是尾结点
	if(listHead->head == NULL)//从无到有
	{
		listHead->head = listHead->tail = newNode;
		return 0;
	}
	
	//第一步:原来链表的尾结点里面的next成员存储 新结点的地址
	listHead->tail->next = newNode;
	//第二步:新节点的prev成员,指向原来链表的尾结点
	newNode->prev = listHead->tail;
	//第三步:更新尾结点
	listHead->tail = newNode;
	
	return 0;
}

5、头插法

/*
函数功能:头插法
返回值:
参数:
*/
int insert_nodeToList_head(struct list *listHead,ElemType_t inputData)
{
		//1、判断listHead是否有效
	if(listHead == NULL)
	{
		printf("listHead is NULL,%s error\n",__FUNCTION__);
		return -1;
	}
	//2、新建结点并且初始化
	Node_t*newNode = new_node(listHead,inputData);
	if(newNode == NULL)
	{
		printf("new_node error\n");
		return -1;
	}
	//如果当前链表没有数据结点,那么新建的这一个结点是链表的首结点也是尾结点
	if(listHead->head == NULL)//从无到有
	{
		listHead->head = listHead->tail = newNode;
		return 0;
	}
	
	//第一步:新结点的next成员存储原来链表的首结点的地址
	newNode->next = listHead->head;
	//第二步:原来链表的首结点里面的prev成员存储新结点的地址
	listHead->head->prev = newNode;
	//第三步:更新头结点
	listHead->head = newNode;
	return 0;
}

 6、查找

/*
函数功能:查找
返回值:
参数:
*/
bool find_nodeToList(struct list *listHead,ElemType_t findData)
{
	if(isEmpty(listHead))
	{
		printf("isEmpty ,%s error\n",__FUNCTION__);
		return false;
	}
	
	bool isFindFlag = falag;
	//遍历链表,挨个元素与findData进行比较
	Node_t *p = listHead->head;
	while(p)
	{
		if(p->data == findData)
		{
			isFindFlag = true;
			break;
		}
		p = p->next;
	}
	return isFindFlag;
}

7、修改

/*
函数功能:修改
返回值:
参数:
*/
bool update_nodeToList(struct list *listHead,ElemType_t srcData,ElemType_t updata)
{
	if(isEmpty(listHead))
	{
		printf("isEmpty ,%s error\n",__FUNCTION__);
		return false;
	}
	//遍历链表,找到你要值尾srcData的结点--找到你要修改的结点
	Node_t *p = listHead->head;
	while(p)
	{
		if(p->data == srcData)
		{
			break;
		}
		p = p->next;
	}
	//如果没有找到,直接返回false
	if(p == NULL)
	{
		return false;
	}
	//4、找到了,直接修改数据
	p->data = updata;
	return true;
}

8、删除

中间删除

 

 尾删除

 

头删除

 

/*
函数功能:删除
返回值:
参数:
*/
bool delete_nodeToList(struct list *listHead,ElemType_t delData)
{
	if(isEmpty(listHead))
	{
		printf("isEmpty ,%s error\n",__FUNCTION__);
		return false;
	}
	
	//如果你当前删除的结点是首结点
	if(listHead->head->data == delData)
	{
		Node_t *delNode = listHead->head;
		//第一步:更新首结点
		listHead->head = listHead->head->next;
		//第二步:删除结点断链接
		delNode->next = NULL;
		//第三步:新的首结点的Prev成员指向NULL
		listHead->head->prev = NULL;
		//第四步:释放删除结点的内存空间
		free(delNode);
		listHead->nodeNumber--;
		return true;
	}
	
	//2、遍历链表,先找到你要删除的那个结点
	Node_t* p = listHead->head;
	bool isFindFlag = false;
	
	while(p)
	{
		if(p->data == delData)
		{
			isFindFlag = true;
			break;
		}
		p = p->next;
	}
	if(isFindFlag == false)
		return false;
	
	if(p == listHead->tail)
	{
		//第一步:更新尾结点
		listHead->tail = p->prev;
		//第二步:尾结点断链接
		listHead->tail->next = NULL;
		//第三步:删除结点断链接
		p->prev = NULL;
		//第四步:释放删除结点的内存空间
		free(p);
	}
	else
	{
		p->prev->next = p->next;
		p->next->prev = p->prev;
		p->next = NULL;
		P->prev = NULL;
		free(p);
	}
	listHead->nodeNumber--;
	
	return true;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值