数据结构与算法(3)——C语言实现线性表之循环双向链表

在循环双向链表存储结构中,每个结点都有两个指针域:prior和next,prior指向直接前驱,next指向直接后继,最后一个结点的next指向头结点,头结点的prior指向最后一个结点。显然,通过指向结点的指针p的p->next可以直接得到某结点的后继结点地址,也可以通过p->prior直接得到某结点的前驱结点的地址,而p->prior->next表示的是p自身存储的地址;同样,p->next->prior也是p本身存储的地址。

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

typedef int ElemType;

typedef struct Node
{
	ElemType elem;
	struct Node* next;
	struct Node* prior;
}Node,*Ptr;

typedef Ptr *SqLisrPtr;

typedef enum Status
{
	success, fial, fatal, range_error
}Status;

Status List_Retrieve(SqLisrPtr L, int pos, ElemType* elem)
{
	Status s = range_error;
	Ptr p = (*L)->next;
	int i = 0;

	while (p != *(L) && i < pos)
	{
		p = p->next;
		i++;
	}
	if (p != (*L) && i == pos)
	{
		*elem = p->elem;
		s = success;
	}

	return s;
}

Status List_Locate(SqLisrPtr L, ElemType elem, int* pos)
{
	Status s = range_error;
	Ptr p = (*L)->next;
	int i = 0;

	while (p != (*L))
	{
		if (p->elem == elem)
		{
			break;
		}
		i++;
		p = p->next;
	}
	if (p != (*L))
	{
		*pos = i;
		s = success;
	}

	return s;
}

Status List_SetPosition(SqLisrPtr L, int pos,Ptr* ptr)
{
	Status s = range_error;
	Ptr p = (*L)->next;
	int i = 0;

	if (pos == -1)
	{
		*ptr = (*L);
		s = success;
		return s;
	}
	while (p != (*L) && i < pos)
	{
		p = p->next;
		i++;
	}
	if (p != (*L) && i == pos)
	{
		*ptr = p;
		s = success;
	}

	return s;
}

Status List_Insert(SqLisrPtr L, int pos, ElemType elem)
{
	Status status;
	Ptr p, s;

	status = List_SetPosition(L, pos - 1, &p);
	if (status == success)
	{
		s = (Ptr)malloc(sizeof(Node));
		if (s)
		{
			s->elem = elem;
			s->next = p->next;
			p->next = s;
			s->next->prior = s;
			s->prior = p;
			status = success;
		}
		else
		{
			status = fatal;
		}
	}
	else
	{
		status = range_error;
	}

	return status;
}

Status List_Remove(SqLisrPtr L, int pos)
{
	Status status;
	Ptr p, s;

	status = List_SetPosition(L, pos - 1, &p);
	if (status == success)
	{
		s = p->next;
		p->next = s->next;
		p->next->prior = p;
		free(s);
		s = NULL;
		status = success;
	}

	return status;
}

Status List_Init(SqLisrPtr L)
{
	Status status = fatal;

	(*L) = (Ptr)malloc(sizeof(Node));
	if (*L)
	{
		(*L)->next = *L;
		(*L)->prior = *L;
		status = success;
	}

	return status;
}

void List_Clear(SqLisrPtr L)
{
	Ptr p, q;

	p = (*L);
	q = p->next;
	while (q != (*L))
	{
		p->next = q->next;
		free(q);
		q = p->next;
	}
}

void List_Destroy(SqLisrPtr L)
{
	List_Clear(L);
	free((*L));
}

bool List_Empty(SqLisrPtr L)
{
	return (*L)->next == (*L);
}

int List_Size(SqLisrPtr L)
{
	int length = 0;
	Ptr p = (*L)->next;

	while (p != (*L))
	{
		p = p->next;
		length++;
	}

	return length;
}

Status List_Prior(SqLisrPtr L, int pos, ElemType* elem)
{
	Status status;
	Ptr p;

	status = List_SetPosition(L, pos - 1, &p);
	if (status == success)
	{
		*elem = p->elem;
	}

	return status;
}

Status List_Next(SqLisrPtr L, int pos, ElemType* elem)
{
	Status status;
	Ptr p;

	status = List_SetPosition(L, pos + 1, &p);
	if (status == success)
	{
		*elem = p->elem;
	}

	return status;
}

Status List_Create(SqLisrPtr L, ElemType* elem, int len)
{
	Status s;

	s = List_Init(L);
	if (s == success)
	{
		for(int i = len -1; i >=0; i--)
		{
			List_Insert(L, 0, elem[i]);
		}
	}

	return s;
}

void List_Show(SqLisrPtr L)
{
	Ptr p = (*L)->next;

	while (p != (*L))
	{
		printf("%d ", p->elem);
		p = p->next;
	}
	printf("\n");
}

int main()
{
	SqLisrPtr L = (SqLisrPtr)malloc(sizeof(Ptr));
	Status status;
	ElemType my_elem[5] = { 1,2,3,4,5 };

	if ((status = List_Create(L,my_elem,5)) != success)
	{
		printf("create error\n");
		exit(-1);
	}
	printf("created\n");
	
	return 0;
}

总结:单链表只能从头结点开始遍历整个链表,而循环双向链表可以从任意结点开始遍历整个链表。另外,单链表访问直接前驱只能从链表的头结点开始,顺着各结点的next域进行,其时间复杂度为O(n),循环双向链表可以通过p->prior直接访问其直接前驱,时间复杂度为O(1)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值