线性表.04.链式存储结构(双向循环链表)

以下是用双向循环链表实现的线性表

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

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int ElemType;//ElemType这里假设为int,可以根据需要进行更改
typedef int Status;//Status是函数的类型,其值是函数结果状态代码,如OK等

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

/*初始化双向循环链表*/
Status InitList(DulNode **L)
{
	*L=(DulNode *)malloc(sizeof(DulNode));
	if(!(*L))
		return ERROR;

	(*L)->next=(*L)->prior=*L;

	return OK;
}

/*初始条件:链式线性表L已存在*/
/**操作结果:返回L中数据元素个数*/
int ListLength(DulNode *L)
{
	int i=0;
	DulNode *p=L->next;
	while(p!=L)
	{
		p=p->next;
		i++;
	}

	return i;
}

/*初始条件:双向循环链表L已存在,1≤i≤ListLength(L)+1*/
/*操作结果:在L中第i个位置插入新的数据元素e,L的长度加1*/
Status ListInsert(DulNode *L,int i,ElemType e)
{
	int j;
	DulNode *p,*s;//p指向要插入位置的前一个结点,s为新结点

	if(i<1)//插入位置不合理
		return ERROR;

	p=L;
	j=1;

	while(j<i)/*寻找第i个结点的前一个结点*/
	{
		p=p->next;
		j++;
		if(p==L)//未找到
			return ERROR;
	}

	s=(DulNode *) malloc(sizeof(DulNode));
	s->data=e;
	s->prior=p;
	s->next=p->next;
	p->next->prior=s;
	p->next=s;

	return OK;
}

/*初始条件:双向循环链表L已存在/
/*操作结果:输出L的每个数据元素*/
Status ListTraverse(DulNode *L)
{
	DulNode *p=L->next;
	while(p!=L)
	{
		printf("%d ",p->data);
		p=p->next;
	}
	printf("\n");

	return OK;
}

/*初始条件:双向循环链表L已存在。
/*操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(DulNode *L)
{
	if(L->next==L && L->prior==L)
		return TRUE;
    else
        return FALSE;
}

/*初始条件:双向循环链表L已存在。*/
/*操作结果:将L重置为空表。*/
Status ClearList(DulNode *L)
{
	DulNode *p;//p指向第一个结点

	p=L->next;
	while(p!=L)
	{
		p=p->next;
		free(p->prior);
	}
	L->next=L->prior=L;//头结点的两个指针域指向其自己

	return OK;
}

/*初始条件:双向循环链表L已存在,1≤i≤ListLength(L)*/
/*操作结果:用e返回L中第i个数据元素的值*/
Status GetElem(DulNode *L,int i,ElemType *e)
{
	DulNode *p;
	int j;

	if(i<1)//取值位置不合理
		return ERROR;

	p=L->next;//p指向第一个结点
	j=1;
	while(p!=L&&j<i)
	{
		p=p->next;
		j++;
	}

	if(p==L)//第i个数据元素不存在
		return ERROR;
	*e=p->data;

	return OK;
}

/*初始条件:双向循环链表L已存在*/
/*操作结果:返回L中第1个与e满足关系的数据元素的位序。*/
/*若这样的数据元素不存在,则返回值为0*/
Status LocateElem(DulNode *L,ElemType e)
{
    int i=0;
    DulNode *p=L->next;
    while(p!=L)
    {
        i++;
        if(p->data==e) /* 找到这样的数据元素 */
                return i;
        p=p->next;
    }

    return 0;
}

/*初始条件:双向循环链表L已存在,1≤i≤ListLength(L)*/
/*操作结果:删除L的第i个数据元素,并用e返回其值*/
Status ListDelete(DulNode *L,int i,ElemType *e)
{
	DulNode *p;//p指向第i个结点
	int j;

	p=L->next;
	j=1;

	if(i<1)//删除位置不合理
		return ERROR;

	while(p!=L&&j<i)
	{
		p=p->next;
		j++;
	}

	if(p==L)//第i个数据元素不存在
		return ERROR;

	*e=p->data;
	p->prior->next=p->next;
	p->next->prior=p->prior;
	free(p);

	return OK;
}

/*初始条件:双向循环链表L已存在/
/*操作结果:返回L中第一个数据元素值为cur_e的前驱结点的值pre_e*/
Status PriorElem(DulNode *L,ElemType cur_e,ElemType *pre_e)
{
	DulNode *p;
	p=L->next;
	while(p!=L)
	{
		if(p->data==cur_e)//找到数据元素cur_e结点
		{
			if(p->prior==L)//如果该结点是第一个结点
				return ERROR;

			*pre_e=p->prior->data;
			return OK;
		}
		p=p->next;
	}

	return ERROR;
}

/*初始条件:双向循环链表L已存在/
/*操作结果:返回L中第一个数据元素值为cur_e的后继结点的值pre_e*/
Status NextElem(DulNode *L,ElemType cur_e,ElemType *next_e)
{
	DulNode *p;
	p=L->next;
	while(p!=L)
	{
		if(p->data==cur_e)//找到数据元素cur_e结点
		{
			if(p->next==L)//如果该结点是最后一个结点
				return ERROR;

			*next_e=p->next->data;
			return OK;
		}
		p=p->next;
	}

	return ERROR;
}

int main()
{
	DulNode *L;//头指针

	int i,j,k;
	ElemType e;
	Status s;

	InitList(&L);
	printf("初始化L后:ListLength(L) = %d\n",ListLength(L));	

	for(j=1;j<=5;j++)
            i=ListInsert(L,1,j);
	printf("在L的表头依次插入1~5后:L.data = ");
    ListTraverse(L); 

	printf("ListLength(L)=%d \n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i = %d(1:是 0:否)\n",i);

	i=ClearList(L);
    printf("清空L后:ListLength(L) = %d\n",ListLength(L));
    i=ListEmpty(L);
    printf("L是否空:i = %d(1:是 0:否)\n",i);

	for(j=1;j<=10;j++)
            ListInsert(L,j,j);
    printf("在L的表尾依次插入1~10后:L.data = ");
    ListTraverse(L);
	printf("ListLength(L) = %d \n",ListLength(L));

	ListInsert(L,1,0);
    printf("在L的表头插入0后:L.data = ");
    ListTraverse(L);
    printf("ListLength(L) = %d \n",ListLength(L));

	GetElem(L,5,&e);
    printf("第5个元素的值为:%d\n",e);

	for(j=3;j<=4;j++)
    {
        k=LocateElem(L,j);
        if(k)
            printf("值为%d的元素的位序为%d\n",j,k);
        else
            printf("没有值为%d的元素\n",j);
    }

	k=ListLength(L); //k为表长
    for(j=k+1;j>=k;j--)
    {
        i=ListDelete(L,j,&e); //删除第j个数据
        if(i==ERROR)
            printf("删除第%d个数据失败\n",j);
        else
            printf("删除第%d个的元素值为:%d\n",j,e);
    }
    printf("依次输出L的元素:");
    ListTraverse(L); 

	j=5;
    ListDelete(L,j,&e); //删除第5个数据
    printf("删除第%d个的元素值为:%d\n",j,e);
    printf("依次输出L的元素:");
    ListTraverse(L); 

	i=ClearList(L);
    printf("\n清空L后:ListLength(L) = %d\n",ListLength(L));

	for(j=1;j<=10;j++)
            ListInsert(L,j,j);
    printf("在L的表尾依次插入1~10后:L.data = ");
    ListTraverse(L);
	printf("ListLength(L) = %d \n",ListLength(L));

	printf("\n前驱判断\n");
	for(j=1;j<=10;j++)
	{
		s=PriorElem(L,j,&e);
		if(s==ERROR)
			printf("元素%d没有前驱\n",j);
		else
			printf("元素%d的前驱是%d\n",j,e);
	}

	printf("\n后继判断\n");
	for(j=1;j<=10;j++)
	{
		s=NextElem(L,j,&e);
		if(s==ERROR)
			printf("元素%d没有后继\n",j);
		else
			printf("元素%d的后继是%d\n",j,e);
	}

}
时间: 2024-10-20 01:59:09

线性表.04.链式存储结构(双向循环链表)的相关文章

数据结构_线性表_链式存储_双向循环链表的基本操作

//双向链表,将头结点和尾结点链接起来,就构成了双向循环链表 //双向循环链表是将头结点的前驱指针指向了尾结点,同时将尾结点的后劲指针指向了头结点. //空表,头结点的前驱和后继指针均指向了自己,这也是判断双向循环链表是否为空的条件, //双向循环链表具有对称性 //缺点,是要付出空间代价的 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点.一般我们都构造双向循环链表. 代

数据结构之线性表(链式存储结构)

线性表的实现分顺序存储结构和链式存储结构 上一节我们主要介绍了顺序存储结构,在最后我们还分别总结了顺序存储结构的优缺点, 对于顺序结构的缺点,我们有没有什么好的解决方法呢? 我们今天要介绍的线性表的链式存储结构就可以很好的解决顺序结构的缺点,一起来看. 顺序结构最大的缺点就是在进行插入和删除操作的时候,如果插入位置不理想,那么我们需要移动大量的元素,那产生这一问题的原因是什么呢? 仔细分析后,我们可以发现在顺序存储结构中,他们相邻的元素的存储位置也是相邻的,我们在申请内存的的时候,是一次性申请一

线性表的链式存储结构

1 n个结点链结成一个链表,即为线性表的链式存储结构,由于每一个结点只包含一个指针域,因此称为单链表. 链表中第一个结点的存储位置成为头指针,那么整个链表的存取就必须是从头指针开始了. 有时候会在单链表的第一个结点前附设一个结点,称为头结点. 头指针与头结点的区别: 头指针: (1)头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针. (2)头指针具有标识作用,所以常用头指针冠以链表的名字. (3)无论链表是否为空,头指针都不为空.头指针是链表的必要元素. 头结点: (1)

【数据结构】-线性表的链式存储结构

引言:由于线性表的顺序存储结构在插入和删除时需要大量移动数据元素,从而引入线性表的链式存储结构. 线性表的链式存储结构:用一组任意的存储单元(可以连续也可以不连续)存储线性表的数据元素. 为了表示数据元素ai和其直接后继ai+1之间的逻辑关系,对ai来说,除了存储其本身的数据信息外,还需要存储其直接后继的存储位置.这两部分信息组成数据元素ai的存储映像(结点).它包含两个域:其中存储数据元素信息的域称为数据域:存储直接后继存储位置的域称为指针域. n个结点链接成一个链表,称为线性链表,由于此链表

数据结构开发(5):线性表的链式存储结构

0.目录 1.线性表的链式存储结构 2.单链表的具体实现 3.顺序表和单链表的对比分析 4.小结 1.线性表的链式存储结构 顺序存储结构线性表的最大问题是: 插入和删除需要移动大量的元素!如何解决? 链式存储的定义: 为了表示每个数据元素与其直接后继元素之间的逻辑关系:数据元素除了存储本身的信息外,还需要存储其直接后继的信息. 链式存储逻辑结构: 基于链式存储结构的线性表中,每个结点都包含数据域和指针域 数据域:存储数据元素本身 指针域:存储相邻结点的地址 专业术语的统一: 顺序表 基于顺序存储

数据结构--线性表的链式存储结构

一 线性表的链式存储结构 A.链式存储的定义为了表示每个数据元素与直接后继元素之间的逻辑关系:数据元素除了存储本身的信息外,还需要存储其直接后继的信息图示B链式存储逻辑结构基于链式存储结构的线性表中,每个结点都包含数据域和指针域1.数据域:存储数据元素本身2.指针域:存储相邻结点的地址图示C链表中的基本概念1.头结点--链表中的辅助结点,包含指向第一个数据元素的指针(方便插入和删除)2.数据结点--链表中代表数据元素的结点,表现形式为:(数据元素,地址)3.尾节点--链表中的最后一个数据结点,包

04.线性表(三)链式存储结构.单链表2

链式存储结构.单链表2 顺序存储结构的创建实质是一个数组的初始化,存储空间连续且其大小和类型已经固定:单链表存储空间不连续,是一种动态结构且它所占用空间的大小和位置是不需要预先分配划定的,可以根据系统的情况和实际的需求即时生成. 一.单链表的整表创建 创建单链表的过程就是一个动态生成链表的过程,即从"空表"的初始化起,依次建立各元素结点,并逐个插入链表. 1.算法思路 (1)声明一个结点p和计数器变量i; (2)初始化一空链表L (3)让链表L的头结点的指针指向NULL,即建立一个带头

七、线性表的链式存储结构

1.问题引入 开发数组类模板的原因在于:在创建基于顺序存储结构的线性表时,发现这样的线性表可能被误用,因为重载了数组访问操作符,使用时跟数组类似,但是线性表和数组有很大的区别,所以激发了新的需求:开发数组类替换C++原生数组类,因为原生数组类也存在着很大缺陷,使用不方便. 基于顺序存储结构的线性表的另一个缺点:插入或删除元素时,涉及到大量数据元素的移动,对于效率的影响非常大 一个新的需求:在插入或删除元素时不需要大量移动数据元素的一种数据结构,即基于链式存储结构的线性表 2.链式结构的定义 为了

线性表的链式存储——线性表的链式存储结构

1,基于顺序存储结构插入或删除元素时候会涉及大量元素移动,非常影响效率,本文着手解决这个问题: 2,链式存储结构为了弥补顺序存储结构效率上的问题: 3,链式存储的定义: 1,为了表示每个数据元素与其后继元素之间的逻辑关系,数据元素除了存储本身的信息外,还需要存储其直接后继的信息: 2,幼儿园排队:每个小朋友记住他前面的小朋友是谁,这样可以轻易的排队: 4,一定要分清 p->next 是左值还是右值,左值时表示节点内存储的位置,右值时表示节点对象: 5,链式存储逻辑结构: 1,基于链式存储结构的线