【数据结构-线性表】双向(循环)链表ADT(严蔚敏《数据结构》)

书里不全,而且有的写的不好。

我全敲出来,测试过,并且底层函数之间没有互相调用(其实完全可以的,但是我就是不,诶,就是玩儿)

并且把里面一些安排的不好的函数优化了一下.

//双向链表ADT

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct Node {
	ElemType data;
	struct Node* prior;
	struct Node* next;
}node, * List;
//小技巧:头结点储存链表长度,还能统一空表和非空表的操作

//函数原型
void Out(ElemType e);//格式化输出
void Print(List L);//正序输出
void PrintDown(List L);//倒序输出

Status InitList(List& L);/*创建空表*/
//Status DestroyList(node* L);//销毁整表
//Status ClearList(node* L);//将L置为空表
bool ListEmpty(List L);//判断是否为空
int ListLength(List L);//返回长度,0和空表都是0

Status GetElem(List L, int i, ElemType& e);//用e返回第i位元素
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp) );//定位到和e满足条件的元素,返回地址,注意编写cmp函数的时候,左边是e,右边是遍历项
node* PriorElem(List L, ElemType cur);//返回cur的前驱,第一个的话就返回L
node* NextElem(List L, ElemType cur);//返回cur的后继,最后一个就返回NULL

Status ListInsert(List L, int i, ElemType e);//把e插入到i位
Status ListDelete(List L, int i, ElemType& e);//删除i位,返回e

Status ListTraverse(List L, Status(*visit)(ElemType& e));//遍历L,执行visit

//函数定义
void Out(ElemType e)
{
	printf("%d\t", e);
}
void Print(List L)
{
	//本算法考虑了空表情况
	node* p = L;
	while (p->next)
	{
		p = p->next;
		Out(p->data);
	}
}
void PrintDown(List L)
{
	//找到尾结点
	node* p = L;
	while (p->next)
		p = p->next;
	//倒序输出
	while (p != L)
	{
		Out(p->data);
		p = p->prior;
	}
}

Status InitList(List &L)
{
	//创建头结点赋值并链接
	node* head = (node*)malloc(sizeof(node));
	if (!head) return ERROR;
	head->data = 0; //长度为0

	L = head;
	head->prior = NULL;
	head->next = NULL;

	return OK;
}
bool ListEmpty(List L)
{
	if (L->data == 0)
		return true;
	else
		return false;
}
int ListLength(List L)
{
	if (L)
		return L->data;
	else
		return ERROR;
}


Status GetElem(List L, int i, ElemType& e)
{
	//本函数采用先查后判断异常的方式
	//令p和index同步采取while循环,因为后面要用index,所以for不如while
	node* p = L;
	int index = 0;
	while (p && index < i)
	{
		p = p->next;
		index++;
	}
	//到这里,成功则index==i,否则就是i小于1或者大于ListLength
	if (!p || i < 1)
		return ERROR;
	else
	{
		e = p->data;
		return OK;
	}
}
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp))
{
	//参数中有一个Status(ElemType,ElemType)型的函数指针
	node* p = L;
	while (p->next)
	{
		p = p->next;
		if (cmp(e, p->data))//直接调用,等价模式
			return p;
	}
	return NULL;
}
node* PriorElem(List L, ElemType cur)
{
	//一般来说是用两个指针pre和p,但是其实双向链表更好实现
	node* p = L;
	while (p->next)
	{
		p = p->next;
		if (cur == p->data)
			return p->prior;
	}
	return NULL;
}
node* NextElem(List L, ElemType cur)
{
	node* p = L;
	while (p->next)
	{
		p = p->next;
		if (p->data == cur)
				return p->next; //不需要判断尾结点,如果是尾结点,就会返回NULL
	}
	return NULL;
}

Status ListInsert(List L, int i, ElemType e)
{
	//本算法为书中优化算法,可以插到i+1位(尾部)
	//查找i-1位,所以存在index为0的情况(插到第一个节点)
	node* p = L;
	int index = 0;
	while (p && index < i - 1)
	{
		p = p->next;
		index++;
	}
	//判断情况
	if (!p || i < 1)
		return ERROR;
	else
	{
		node* newnode = (node*)malloc(sizeof(node));
		if (!newnode) return ERROR;
		newnode->data = e;

		if (p->next)//判断非表尾 
			p->next->prior = newnode;
		newnode->next = p->next;
		p->next = newnode;
		newnode->prior = p;
		L->data++;

		return OK;
	}
}
Status ListDelete(List L, int i, ElemType& e)
{
	//查找i位
	node* p = L;
	node* pre_p = p;
	int index = 0;
	while (p && index < i)
	{
		pre_p = p;
		p = p->next;
		index++;
	}
	//判断情况
	if (!p || i < 1) 
		return ERROR;
	else
	{
		e = p->data;

		if (p->next)//判断非尾部
			p->next->prior = pre_p;
		pre_p->next = p->next;
		free(p);
		L->data--;

		return OK;
	}
}

Status ListTraverse(List L, Status(*visit)(ElemType& e))
{
	node* p = L;
	while (p->next)
	{
		p = p->next;
		if (!visit(p->data))
			return ERROR;
	}
}

Status visit(ElemType&e)
{
	e = e * 10 - 1;
	return OK;
}
int main(void)
{
	node* L = NULL;
	ElemType e = -1;
	node* p = NULL;

	InitList(L);
	for (int i = 1; i <= 5; i++)
		ListInsert(L, i, i);
	Print(L);
	PrintDown(L);
	putchar('\n');
	//下面随便测试
      
	return 0;
}



要解双向约瑟夫环问题了,所以又在原有基础上改成了双向环表

//双向循环链表ADT

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct Node {
	ElemType data;
	struct Node* prior;
	struct Node* next;
}node, * List;
//小技巧:头结点储存链表长度,还能统一空表和非空表的操作

//函数原型
void Out(ElemType e);//格式化输出
void PrintLoop(List L);//正序输出
void PrintLoopDown(List L);//倒序输出

Status InitList(List& L);/*创建空表*/
//Status DestroyList(node* L);//销毁整表
//Status ClearList(node* L);//将L置为空表
bool ListEmpty(List L);//判断是否为空
int ListLength(List L);//返回长度,0和空表都是0

Status GetElem(List L, int i, ElemType& e);//用e返回第i位元素
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp) );//定位到和e满足条件的元素,返回地址,注意编写cmp函数的时候,左边是e,右边是遍历项
//前驱后继可能得根据需求修改了,看你怎么定义前驱后继
node* PriorElem(List L, ElemType cur);//返回cur的前驱,第一个的话就返回L
node* NextElem(List L, ElemType cur);//返回cur的后继,最后一个就返回NULL

Status ListInsert(List L, int i, ElemType e);//把e插入到i位
Status ListDelete(List L, int i, ElemType& e);//删除i位,返回e

Status ListTraverse(List L, Status(*visit)(ElemType& e));//遍历L,执行visit

//函数定义
void Out(ElemType e)
{
	printf("%d\t", e);
}
void PrintLoop(List L)
{
	node* p = L;
	while (p->next != L)//兼容空表
	{
		p = p->next;
		Out(p->data);
	}
	p = p->next;
	while (p->next != L)//兼容空表
	{
		p = p->next;
		Out(p->data);
	}
}
void PrintLoopDown(List L)
{
	//找到尾结点
	node* p = L->prior;
	//倒序输出,兼容空表
	while (p != L)
	{
		Out(p->data);
		p = p->prior;
	}
	p = p->prior;
	while (p != L)
	{
		Out(p->data);
		p = p->prior;
	}
	
}

Status InitList(List &L)
{
	//创建头结点赋值并链接
	node* head = (node*)malloc(sizeof(node));
	if (!head) return ERROR;
	head->data = 0; //长度为0

	L = head;
	head->prior = head;
	head->next = head;

	return OK;
}
bool ListEmpty(List L)
{
	if (L->data == 0)
		return true;
	else
		return false;
}
int ListLength(List L)
{
	if (L)
		return L->data;
	else
		return ERROR;
}

Status GetElem(List L, int i, ElemType& e)
{
	//本函数采用先查后判断异常的方式
	//令p和index同步采取while循环,因为后面要用index,所以for不如while
	node* p = L->next;
	int index = 1;
	while (p != L && index < i)
	{
		p = p->next;
		index++;
	}
	//到这里,成功则index==i,否则就是i小于1或者大于ListLength
	if (p == L || i < 1)
		return ERROR;
	else
	{
		e = p->data;
		return OK;
	}
}
node* LocateElem(List L, ElemType e, Status(*cmp)(ElemType e,ElemType temp))
{
	//参数中有一个Status(ElemType,ElemType)型的函数指针
	node* p = L;
	while (p->next != L)
	{
		p = p->next;
		if (cmp(e, p->data))//直接调用,等价模式
			return p;
	}
	return NULL;
}
node* PriorElem(List L, ElemType cur)
{
	//一般来说是用两个指针pre和p,但是其实双向链表更好实现
	node* p = L;
	while (p->next != L)
	{
		p = p->next;
		if (cur == p->data)
			return p->prior;
	}
	return NULL;
}
node* NextElem(List L, ElemType cur)
{
	node* p = L;
	while (p->next != L)
	{
		p = p->next;
		if (p->data == cur)
			return p->next;
	}
	return NULL;
}

Status ListInsert(List L, int i, ElemType e)
{
	//本算法为书中优化算法,可以插到i+1位(尾部)
	if (i == 1) //第一位特殊处理一下
	{
		node* p = (node*)malloc(sizeof(node));
		if (!p) return ERROR;

		p->data = e;
		p->next = L->next;
		L->next->prior = p;
		L->next = p;
		p->prior = L;
		L->data++;

		return OK;
	}
	else
	{
		//查找i-1位,不存在index为0的情况(插到第一个节点)
		node* p = L->next;
		int index = 1;
		while (p != L && index < i - 1)
		{
			p = p->next;
			index++;
		}
		//判断情况
		if (p == L || i < 1)
			return ERROR;
		else
		{
			node* newnode = (node*)malloc(sizeof(node));
			if (!newnode) return ERROR;
			newnode->data = e;

			p->next->prior = newnode;
			newnode->next = p->next;
			p->next = newnode;
			newnode->prior = p;
			L->data++;

			return OK;
		}
	}
}
Status ListDelete(List L, int i, ElemType& e)
{
	//查找i位,从1开始
	node* p = L->next;
	node* pre_p = L;
	int index = 1;
	while (p != L && index < i)
	{
		pre_p = p;
		p = p->next;
		index++;
	}
	//判断情况
	if (p == L || i < 1)
		return ERROR;
	else
	{
		e = p->data;

		p->next->prior = pre_p;
		pre_p->next = p->next;
		free(p);
		L->data--;

		return OK;
	}
}

Status ListTraverse(List L, Status(*visit)(ElemType& e))
{
	node* p = L;
	while (p->next != L)
	{
		p = p->next;
		if (!visit(p->data))
			return ERROR;
	}
}


//主函数
int main(void)
{
	node* L = NULL;
	node* p = NULL;
	ElemType e = -1;
	node* left = NULL;
	node* right = NULL;

	InitList(L);

	for (int i = 1; i <= 5; i++)
		ListInsert(L, i, i);
	PrintLoop(L);
	PrintLoopDown(L);
	putchar('\n');
	//后面随便测试

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亦梦亦醒乐逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值