【数据结构学习】双向链表的增、删、查、遍历、释放操作的C语言实现

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

单向链表和双向链表优缺点:

双向链表:增加删除节点复杂,需要多分配一个指针存储空间。

双向链表:从双向链表中的任意一个结点开始,都可以很方便地访问前驱结点和后继结点。

单向链表:结点的删除非常方便,不需要像线性结构那样移动剩下的数据,但是平均的访问效率低于线性表。

单向链表:单个结点创建非常方便,普通的线性内存通常在创建的时候就需要设定数据的大小,结点的访问方便,可以通过循环或者递归的方法访问到任意数据。

代码如下:

头文件:

#ifndef __FY_LINKLIST_H
#define __FY_LINKLIST_H

typedef int data_t;

struct node {
	data_t data;
	struct node *prev;
	struct node *next;
};

//创建一个结点
struct node *creatNode(data_t data);
//创建一个双向链表
struct node *creatList(void);
//指定位置插入一个数据
int list_insert(struct node *H,int pos,data_t data);
//删除指定位置的结点
int list_delete(struct node *H,int pos);
//查找指定位置的元素
struct node *list_get(struct node *H,int pos);
//销毁双向链表
struct node *list_free(struct node *H);
//遍历链表
int list_show(struct node *H);
#endif

C文件:

#include "linklist.h"
#include "stdio.h"
#include "stdlib.h"


//创建一个结点
struct node *creatNode(data_t data){
	struct node *newnode = (struct node *)malloc(sizeof(struct node));
	if(newnode == NULL) {
		printf("创建结点失败,申请内存为空!\n");
		return NULL;
	}

	newnode->data = data;
	newnode->prev = NULL;
	newnode->next = NULL;

	return newnode;
}

//创建一个双向链表(头结点)
struct node *creatList(void){
	struct node* newnode = (struct node *)malloc(sizeof(struct node));
	if(newnode == NULL){
		printf("创建双向链表失败,申请内存为空!\n");
		return NULL;
	}

	newnode->data = 0;
	newnode->next = newnode->prev = NULL;

	return newnode;
}

//获取双向链表中指定位置元素
/*
	定义头结点的位置为-1
*/
struct node *list_get(struct node *H,int pos){
	if(H == NULL) return NULL;
	if(pos <-1) return NULL;

	int i=-1;
	struct node *p = H;

	while(i<pos && p!=NULL){
		p = p->next;
		i++;
	}
	if(i!=pos) return NULL;

	return p;

}

//指定位置插入一个数据
/*
	定义头结点位置为-1
*/
int list_insert(struct node *H,int pos,data_t data){
	if(H==NULL)	return -1;
	if(pos<0)	return -1;

	struct node *p = list_get(H,pos-1);//找到该位置的前驱结点
	if(p==NULL)	return -1;

	struct node *newnode = creatNode(data);

	//p结点是肯定存在的
	newnode->prev = p;
	newnode->next = p->next;

	if(p->next != NULL)//p结点存在后继
		p->next->prev = newnode;
	p->next = newnode;
	
	return 0;
}
//删除指定位置的结点
int list_delete(struct node *H,int pos){
	if(H==NULL)	return -1;
	if(pos<0)	return -1;

	struct node *p = list_get(H,pos);
	if(p==NULL)	return -1;

	//p结点是肯定存在的,并且肯定是有前驱的(至少头结点不能被删除)
	p->prev->next = p->next;
	if(p->next != NULL){	//存在后继结点的情况下
		p->next->prev = p->prev;
	}
	free(p);

	return 0;
}
//销毁双向链表
struct node *list_free(struct node *H){
	if(H==NULL)	return NULL;
	
	struct node *p = H;

	while(H->next != NULL){
		H = H->next;
		free(p);
		p = H;
	}free(p);

	return NULL;
}

//遍历链表
int list_show(struct node *H){
	if(H == NULL)	return -1;
	struct node *p = H->next;

	while(p!=NULL){
		printf("%d ",p->data);
		p = p->next;
	}printf("\n");

	return 0;
}

测试代码:

#include "stdio.h"
#include "stdlib.h"
#include "linklist.h"

int main(){
	int pos;
	data_t value;
	struct node *H = creatList();
	printf("**********************指定位置插入结点测试*********************\n");
	while(1){
		printf("请按顺序输入位置和数据,输入-1 -1结束测试:");
		scanf("%d %d",&pos,&value);
		if(pos == -1 && value == -1) {
			printf("测试结束!\n");
			break;
		}
		int res;
		res = list_insert(H,pos,value);
		if(res==0){
			printf("\n插入成功,新链表为:");
			list_show(H);
		}
		else{
			printf("插入失败!\n");
		}
	}
	
	H = list_free(H);
	H = creatList();
	for(int i=0;i<10;i++){
		list_insert(H,i,i);
	}
	list_show(H);

	printf("***********************指定位置查找元素测试********************\n");
	while(1){
		printf("请输入一个位置,输入-1结束测试:");
		scanf("%d",&pos);
		if(pos == -1){
			printf("测试结束!\n");
			break;
		}
		struct node *p = list_get(H,pos);
		if(p == NULL){
			printf("查找失败!\n");
		}
		else{
			printf("查找的元素为:%d\n",p->data);
		}
	}

	printf("***********************删除指定位置结点测试********************\n");
	while(1){
		printf("请按顺序输入位置和数据,输入-1结束测试:");
		scanf("%d",&pos);
		if(pos == -1) {
			printf("测试结束!\n");
			break;
		}
		int res;
		res = list_delete(H,pos);
		if(res == 0){
			printf("删除成功,新链表为:");
			list_show(H);
		}
		else{
			printf("删除失败!\n");
		}
	}

	printf("hell world!\n");
	return 0;
}

测试结果:

指定位置插入

指定位置查找

指定位置删除

 

By urien 2021年2月4日 17:52:16

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值