双向链表--C语言版

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<malloc.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;
typedef int ElemType;
//链表的定义
//这里以学生管理系统为例
//为了统一链表,通常分两部定义
//typedef struct ElemType
//{
	//char num[8];//数据域     学号
	//char name[8];//数据域    姓名 
	//int score;//数据域       成绩
//}ElemType;
typedef struct DuLNode
{
	ElemType date;//数据域
	struct DuLNode* prior;//指向直接前驱
	struct DuLNode* next;//指向直接后继

}DuLNode, * DuLinkList;//LinkList为指向结构体Lnode的指针类型

DuLinkList L;//定义头指针变量

//双向链表的初始化即构造一个空的表
Status linitList_L(DuLinkList L)//  LinkList L 头指针
{
	L = (DuLinkList)malloc(sizeof(DuLNode));//动态获取LNode的字节数,从而开辟新的空间,生成新结点作头结点,用头指针L指向头结点
	if (L == NULL)
	{
		exit(OVERFLOW);
	}
	else
	{
		L->prior = NULL;//指向直接前驱的指针域置空
		L->next = NULL;//指向直接后继的指针域置空
		return OK;
	}
}

//链表判空   判断头结点的指针域是否为空
int ListEmpty(DuLinkList L)
{
	if (L->next == L->prior)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

//链表的销毁  从头指针开始,依次释放所有结点  
Status DestroyList_L(DuLinkList L)
{
	DuLNode* p = L;//要销毁的结点
	while (L)  //循环条件:L!=NULL   结束条件  L==NULL
	{
		p = L;
		L = L->next;//把下一个结点赋值给L 依次free
		free(p);
	}
	return OK;
}

//清空单链表  链表依然存在 成为空链表  依次释放所有结点,并将头结点指针域置空
Status ClearList(DuLinkList L)
{
	DuLNode* p = L, * q;
	p = L->next;//第一个结点
	while (p!=L->prior)
	{
		q = p->next;//q存放下一个结点 关键操作
		free(p);//释放第一个结点
		p = q;//把第二个节点还给p 依次循环释放直到表空
	}
	L->next = NULL;//头结点指针域为空
	return OK;
}

//求链表的表长
int ListLength_L(DuLinkList L)
{
	DuLNode* p = L;
	int i = 0;
	p = L->next;//p指向第一个结点
	while (p!=L->prior)
	{
		i++;
		p = p->next;
	}
	return i;
}

//取值,取第i个元素值s(插入用)
DuLinkList GetElem_DuL(DuLinkList L, int i)//根据第i个元素用e返回其值
{
	DuLNode* p = L;
	p = L->next;
	int j = 1;//初始化
	while (p!=L->prior && j < i)
	{
		p = p->next;//向后扫描,直到p指向第i个元素或p为空
		++j;
	}
	if (!p!=L->prior || j > i)//第i个元素不存在
	{
		return ERROR;
	}
	else
	{
		return p;
	}
}

//取值,取第i个元素值s
int GetElem_L(DuLinkList L, int i, ElemType* e)//根据第i个元素用e返回其值
{
	DuLNode* p = L->next;
	int j = 1;//初始化
	while (p!=L->prior && j < i)
	{
		p = p->next;//向后扫描,直到p指向第i个元素或p为空
		++j;
	}
	if (!p!=L->prior || j > i)//第i个元素不存在
	{
		return ERROR;
	}
	else
	{
		*e = p->date;//取第i个元素
		return OK;
	}
}
查找  按值查找 返回地址
//int LocateELem_L(DuLinkList L, ElemType e)
//{
//	//在线性表L中查找值为e的数据元素
//	//找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
//	DuLNode* p = L->next;
//
//	while (p!=L->prior && p->date != e)
//	{
//		p = p->next;
//
//	}
//	return p;
//}


int LocateELem_L(DuLinkList L, ElemType e)
{
	DuLNode* p = L;
	p = L->next;//初始化,p指向首元结点
	int j = 1;

	while (p!=L->prior && (p->date != e))
	{
		p = p->next;
		j++;
	}
	if (!p!=L->prior)//如果p为空,也就是没找到为假,返回else的值0
		  //如果p找到了,那么p就不为0 执行返回j
	{
		return 0;
	}
	else
	{
		return j;
	}
}

//插入 在第i个结点前插入值为e的新结点
Status LintInsert_L(DuLinkList L, int i, ElemType e)
{
	DuLNode* p = L;//定义一个结点
	//int j = 0;//计数器  从头结点开始
	if (!(p = GetElem_DuL(L, i))) return ERROR;
	else
	{
		DuLNode* s = (DuLNode*)malloc(sizeof(DuLNode));//生成新结点
		if (s == NULL)
		{
			exit(ERROR);
		}
		else
		{
			s->date = e;//将新结点的数据域置为e
			s->prior = p->prior;//把前一结点的地址给新结点的prior  前一结点的地址存在后一结点的prior中
			p->prior->next = s;//把新结点地址放在前驱结点的直接后继指针域
			s->next = p;
			p->prior = s;
			return OK;
		}
	}
}

//删除第i个结点    将线性表L中第i个数据元素删除
Status ListDelete_L(DuLinkList L, int i, ElemType* e)//这里需要对数据域进行操作需要传递指针
{
	DuLNode* p = L;
	if(!(p=GetElem_DuL(L,i)))
	{
		return ERROR;
	}
	else
	{
		*e = p->date;
		p->prior->next = p->next;
		p->next->prior = p->next;
		free(p);
		return OK;
	}
}

//头插法建立单链表   L是头结点
//DuLinkList CreateList_H(DuLinkList L, int n)//n是结点数即要插入多少个结点
//{
//	L = (DuLinkList)malloc(sizeof(DuLNode));//生成头结点
//	if (L == NULL)
//	{
//		exit(ERROR);
//	}
//	else
//	{
//		L->next = NULL;
//	}
//	int i = 0;
//	for (i = n; i > 0; --i)
//	{
//		LNode* p = (LNode*)malloc(sizeof(LNode));//生成新结点
//		if (p == NULL)
//		{
//			exit(ERROR);
//		}
//		else
//		{
//			printf("请输入第%d个结点数据域", i);
//			scanf_s("%d", &p->date);//输入元素值
//			p->next = L->next;//插入到表头 把头结点的指针域赋给新结点的指针域
//			L->next = p;//再把新结点的指针赋给头结点的指针域
//		}
//	}
//	return L;
//}

//尾插法建立单链表  正位序输入n个元素的值
DuLinkList CreateList_R(DuLinkList L, int n)
{
	L = (DuLinkList)malloc(sizeof(DuLNode));//分配空间
	if (L == NULL)
	{
		exit(ERROR);
	}
	else
	{
		L->prior = NULL;
		L->next = NULL;
	}
	DuLNode* r = L;//这里的r为尾指针,只有一个结点时,头指针与尾指针同时指向头结点
	for (int i = 0; i < n; ++i)
	{
		DuLNode* p = (DuLNode*)malloc(sizeof(DuLNode));//生成新结点
		if (p == NULL)
		{
			exit(ERROR);
		}
		else
		{
			scanf_s("%d", &p->date);//输入元素值

			p->next = NULL;
			p->prior = r;
			r->next = p;//把新结点的地址给上一个结点的指针域
			r = p;//r指向新的尾结点
		}
	}
	return L;
}

void PrintLinkList(DuLinkList L)
{
	DuLNode* p = L->next;
	while (p!=NULL)
	{
		printf("-->%d<-- ", p->date);
		p = p->next;
	}
	printf("\n");
}

void menu()
{
	printf("*******************************\n");
	printf("*     1.头插法建立链表        *\n");
	printf("*     2.尾插法建立链表        *\n");
	printf("*     3.查找位置              *\n");
	printf("*     4.删除结点              *\n");
	printf("*     5.插入结点              *\n");
	printf("*     6.查值                  *\n");
	printf("*     7.链表表长              *\n");
	printf("*     8.清空链表              *\n");
	printf("*     9.销毁链表              *\n");
	printf("*     10.查看链表             *\n");
	printf("*******************************\n");
}
int main()
{
	int a = 0;
	menu();
	int n = 0;

	while (!a)
	{
		scanf_s("%d", &n);
		switch (n)
		{
		case 1:
		{
			int n = 0;
			printf("请输入要插入的结点数:");
			scanf_s("%d", &n);
			linitList_L(L);
			//L = CreateList_H(L, n);
			printf("\n插入成功!!\n");
			break;
		}
		case 2:
		{
			int n = 0;
			printf("请输入要插入的结点数:");
			scanf_s("%d", &n);
			linitList_L(L);
			L = CreateList_R(L, n);
			printf("\n插入成功!!\n");
			break;
		}
		case 3:
		{
			ElemType e = 0;
			int sum = 0;
			printf("\n请输入要查找的值:");
			scanf_s("%d", &e);
			sum = LocateELem_L(L, e);
			if (sum == 0)
			{
				printf("查找失败\n");
			}
			else
			{
				printf("你所查的值的位置在第%d个结点\n", sum);
			}
			break;
		}
		case 4:
		{
			int e = 0;
			int i = 0;
			int sum = 0;
			printf("请输入要删除的位置:\n");
			scanf_s("%d", &i);
			sum = ListDelete_L(L, i, &e);
			if (sum == ERROR)
			{
				printf("结点不存在或输入错误\n");
			}
			else
			{
				printf("该结点已删除,删除的结点为:%d\n", e);
			}
			break;
		}
		case 5:
		{
			int i = 0;//结点的位置
			int e = 0;
			int sum = 0;
			printf("\n请输入要插入的位置:");
			scanf_s("%d", &i);
			printf("\n请输入要插入的值:");
			scanf_s("%d", &e);
			sum = LintInsert_L(L, i, e);
			if (sum == ERROR)
			{
				printf("插入失败:输入位置不合法\n");
			}
			else
			{
				printf("插入成功\n");
			}
			break;
		}
		case 6:
		{
			int i = 0;//位置
			int sum = 0;
			int e = 0;
			printf("\n请输入要查询的位置:");
			scanf_s("%d", &i);
			sum = GetElem_L(L, i, &e);
			if (sum == ERROR)
			{
				printf("该结点不存在\n");
			}
			else
			{
				printf("该结点的值为:%d\n", e);
			}
			break;
		}
		case 7:
		{
			int i = 0;
			i = ListLength_L(L);
			printf("该链表表长为:%d\n", i);
			break;
		}
		case 8:
		{
			int i = 0;
			i = ClearList(L);
			if (i == OK)
			{
				printf("链表清空成功\n");
			}
			break;
		}
		case 9:
		{
			int i = 0;
			i = DestroyList_L(L);
			if (i == OK)
			{
				printf("链表销毁成功\n");
				return 0;

			}
			break;
		}
		case 10:
		{
			int i = 0;
			i = ListEmpty(L);
			if (i == 0)
			{
				printf("该链表为空\n");
			}
			else
			{
				printf("该链表不为空\n");
			}
			PrintLinkList(L);
			break;
		}
		}
	}


	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双向链表多级菜单设计是一种常见的数据结构和算法应用,可以用于实现多级菜单的设计。在C语言中,可以通过定义结构体和使用指针来实现双向链表的设计。 首先,我们需要定义一个双向链表节点的结构体,包含菜单项的名称、指向上一级菜单的指针、指向下一级菜单的指针以及指向子菜单的指针。例如: ```c typedef struct MenuItem { char name[50]; struct MenuItem* prev; struct MenuItem* next; struct MenuItem* child; } MenuItem; ``` 接下来,我们可以编写一些函数来实现双向链表多级菜单的操作,包括创建菜单项、添加子菜单、添加兄弟菜单等。以下是一个简单的示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> MenuItem* createMenuItem(const char* name) { MenuItem* item = (MenuItem*)malloc(sizeof(MenuItem)); strcpy(item->name, name); item->prev = NULL; item->next = NULL; item->child = NULL; return item; } void addChild(MenuItem* parent, MenuItem* child) { if (parent->child == NULL) { parent->child = child; child->prev = NULL; child->next = NULL; } else { MenuItem* lastChild = parent->child; while (lastChild->next != NULL) { lastChild = lastChild->next; } lastChild->next = child; child->prev = lastChild; child->next = NULL; } } void addSibling(MenuItem* sibling, MenuItem* newSibling) { sibling->next = newSibling; newSibling->prev = sibling; newSibling->next = NULL; } void printMenu(MenuItem* menu) { MenuItem* currentItem = menu; while (currentItem != NULL) { printf("%s\n", currentItem->name); if (currentItem->child != NULL) { printMenu(currentItem->child); } currentItem = currentItem->next; } } int main() { MenuItem* menu = createMenuItem("Menu"); MenuItem* item1 = createMenuItem("Item 1"); MenuItem* item2 = createMenuItem("Item 2"); MenuItem* item3 = createMenuItem("Item 3"); addChild(menu, item1); addChild(menu, item2); addChild(menu, item3); MenuItem* subItem1 = createMenuItem("Sub Item 1"); MenuItem* subItem2 = createMenuItem("Sub Item 2"); addChild(item1, subItem1); addChild(item1, subItem2); MenuItem* siblingItem = createMenuItem("Sibling Item"); addSibling(item3, siblingItem); printMenu(menu); return 0; } ``` 上述代码中,我们首先创建了一个名为"Menu"的菜单项,然后创建了三个子菜单项"Item 1"、"Item 2"和"Item 3",并将它们添加到"Menu"菜单项中。接着,我们创建了两个子菜单项"Sub Item 1"和"Sub Item 2",并将它们添加到"Item 1"菜单项中。最后,我们创建了一个兄弟菜单项"Sibling Item",并将它添加到"Item 3"菜单项后面。 通过调用printMenu函数,我们可以打印出整个菜单的结构。 希望以上内容能够帮助到你!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值