C语言实现双向循环链表

本文介绍了C语言如何实现双向循环链表,包括结构体定义、简单实现及总结。双向链表每个节点包含两个指针,分别指向前后节点,提供更灵活的访问方式,虽然空间消耗增加,但能提升某些操作的时间效率。
摘要由CSDN通过智能技术生成

C语言实现双向循环链表

本篇是关于双向循环链表的简单实现,有错漏的地方请在评论区评价。

双向链表是在单链表的每个结点中,再设置一个指向其前驱结点的指针域。所以在双向链表中的结点都有两个指针域,一个指向直接后继,另一个指向直接前驱。

结构体

/* 线性表的双向链表存储结构 */
typedef struct DulNode{
    ElemType data;	//数据域
    struct DulNode *prior;	//直接前驱指针
    struct DulNode *next;	//直接后继指针
}DulNode, *DulLinkList;

简单实现

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

#define ERROR 0
#define FALSE 0
#define TRUE 1
typedef int ElemType;
typedef int Status;

/* 双向循环链表 */ 
typedef struct DulNode{
	ElemType data;	//数据域
	struct DulNode* prior;	//直接前驱
	struct DulNode* next;	//直接后继 
}DulNode;

typedef struct DulNode* LinkList;

/* 遍历方法 */
void display(LinkList list){
	LinkList p = list;
	int i=1;
	while(p->next != list){
		p = p->next;
		printf("第%d个数值是%d\n",i++,p->data);
	}
}

/* 初始化函数 */
LinkList initList(int n){
	int i;
	LinkList list = (LinkList)malloc(sizeof(DulNode));	//头结点
	list->data = 0;
	list->prior = list;
	list->next = list;
	LinkList p = list; 
	printf("输入%d个数值(空格分隔):\n",n); 
	for(i=0;i<n;i++){
		LinkList newNode = (LinkList)malloc(sizeof(DulNode));	//生成新结点
		scanf("%d",&newNode->data);
		newNode->prior = p;
		newNode->next = NULL;
		p->next = newNode;
		p = p->next;
	}
	p->next = list;
	list->prior = p;
	list->data = n;
	return list;
}

/* 插入 */
Status insertElem(LinkList list, int n ,ElemType e){
	if(n<1){
		printf("索引值小于1,非法插入!\n");
		return ERROR;	
	}else if(n>list->data+1){
		printf("索引值大于链表最大长度,非法插入!\n");
		return ERROR;
	}else{
		LinkList p = list;
		while(--n){
			p = p->next;
		}
		LinkList newNode = (LinkList)malloc(sizeof(DulNode));	//新结点
		newNode->data = e;
		p->next->prior = newNode;
		newNode->next = p->next;	
		newNode->prior = p;
		p->next = newNode;
		list->data++;
		return TRUE;
	}
}

//查找
Status searchElem(LinkList list, int n, ElemType *e){
	if(n<1){
		printf("索引值小于1,非法查询!\n");
		return ERROR; 
	}else if(n>list->data){
		printf("索引值大于链表长度,非法查询!\n");
		return ERROR; 
	}else{
		LinkList p = list;
		while(n--){
			p = p->next;
		}
		*e = p->data;
		return TRUE;
	}
} 

/* 单个删除 */
Status deleteElem(LinkList list, int n){
	if(n<1){
		printf("索引值小于1,非法删除!\n");
		return ERROR;
	}else if(n>list->data){
		printf("索引值大于链表长度,非法删除!\n");
		return ERROR;
	}else{
		LinkList p = list;
		while(--n){
			p = p->next;
		}
		LinkList q = p->next;
		q->next->prior = p;
		q->prior = NULL;
		p->next = q->next;
		free(q);
		list->data--;
		return TRUE;
	}
}

/* 全表删除 */
void deleteList(LinkList list){
	LinkList p;
	while(list->next != list){
		p = list->next;
		list->next = p->next;
		p->prior = NULL;
		p->next->prior = list;
		p->next = NULL;
		free(p);
	} 
	list->data = 0;
} 
 
/* 主函数 */ 
int main(){
	int initNum;	//初始化个数 
	LinkList list;
	int insertSize,insertNum;	//输入的位置和数值 
	int searchSize,searchNum;	//查找的位置 
	ElemType *e = &searchNum;
	int deleteSize;	//删除位置	
	Status continueFlag = TRUE;	//默认循环 
	int functionNum;	//功能号 
	
	while(continueFlag){
		printf("---------菜单----------\n");
		printf("--------1.初始化-------\n");
		printf("--------2.查找---------\n");
		printf("--------3.插入---------\n");
		printf("--------4.单个删除-----\n");
		printf("--------5.全表删除-----\n");
		printf("--------6.退出---------\n");
		printf("输入选择的功能号:\n");
		scanf("%d",&functionNum);
		switch(functionNum){
			case 1:
				printf("输入要输入的数值个数:\n");
				scanf("%d",&initNum);
				list = initList(initNum);
				display(list);
				break;
			case 2:
				//查找
				printf("输入要查找的元素位置:\n");
				scanf("%d",&searchSize);
				if(searchElem(list,searchSize,e)){
					printf("查找成功!第%d个数值是%d\n",searchSize,*e);
				}
				break;
			case 3:
				//插入
				printf("输入要插入的位置和数值(空格分隔):\n");
				scanf("%d %d",&insertSize,&insertNum);
				if(insertElem(list,insertSize,insertNum)){
					printf("插入成功!\n");
					display(list);
				}
				break;
			case 4:
				//单个删除
				printf("输入要删除的数值位置:\n");
				scanf("%d",&deleteSize);
				if(deleteElem(list,deleteSize)){
					printf("删除成功!\n");
					display(list);
				} 
				break;
			case 5:
				//整表删除
				deleteList(list);
				printf("删除成功!\n");
				printf("当前链表长度:%d\n",list->data);
				break; 
			case 6:
				continueFlag = FALSE;
				printf("感谢使用!"); 
				break;
			default:
				printf("功能号不存在!\n");
				break; 
		}
	}
	return 0;
} 

简单总结

​ 双向链表相对于单链表来说,要更复杂一些,因为多了prior指针,对于插入和删除,需要格外小心。另外它由于每个结点都需要记录两份指针,所以在空间上是要占用多一点空间的。不过,由于它有良好的对称性,使得对某个结点的前后结点的操作,带来了方便,可以有效提高算法的时间性能。说白了,就是用空间换时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值