当前位置:首页 » 服务存储 » 循环链表探索存储
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

循环链表探索存储

发布时间: 2022-06-09 05:13:57

‘壹’ 有人说,采用循环链表作为存储结构的队列就是循环队列,这种说法有道理么

没有道理,

‘贰’ 循环链表存储列队时,为什么下标为0的存储单元不用

既然是用链表怎么会有下标?不是指针么?如果你说的是头结点,当然不能用,不然怎么区分你队列的头尾。。。
队列是先进先出,栈是先进后出,都有push和pop操作

‘叁’ 单向循环链表存储结构实现约瑟夫环

# include <stdio.h>
# include <malloc.h>
struct stu
{
int num;
struct stu *next;
};
int m,n;struct stu *p,*q,*s;
struct stu *create()
{
struct stu *head,*s1,*r;
int i;

head=NULL;
for(i=1;i<=n;i++)
{
s1=(struct stu *)malloc(sizeof(struct stu));
s1->num =i;
if(head==NULL)head=s1;
else r->next =s1;
r=s1;
}
if(r) r->next =head;
return head;
}
struct stu * get_index(struct stu *head,int k)
{
int j=1;
if (k<1)
{
printf ("输入错误\n");
return NULL;
}
s=head;
while (s && j<k)
{
s=s->next ;j++;
}
return s;
}
void f1 (struct stu *head,struct stu *h)
{
int x,i;
x=m/2;
p=h;
i=1;printf ("依次出列的人的编号为:");
while (p->next!=p)
{
q=p->next;
for (i=1;i<x;i++)
{p=q->next;q=p->next;}
p->next =q->next ;
printf ("%d ",q->num);
free(q);
p=p->next ;
}
printf ("最后剩下的人的编号为%d\n",p->num );
}
void f2 (struct stu *head,struct stu *h)
{
int i,x;
x=m/2;
i=1;
p=h;
printf ("依次出列的人的编号为:");
do
{
for (i=1;i<=x;i++)
{q=p->next ;p=q->next ;}
q->next =p->next ;
printf ("%d ",p->num);
free(p);
p=q->next ;
}
while (q->next!=q);
printf ("\n最后剩下的人的编号为%d\n",q->num);
}
void main ()
{
int k;
struct stu *head,*h;
printf ("请输入总人数:");
scanf ("%d",&n);
printf ("请输入退出圈子的人的编号:");
scanf("%d",&m);
printf ("请输入开始报数的人的编号:");
scanf ("%d",&k);
head=create ();
h=get_index(head,k);
if (m%2==0) f1(head,h);
else f2(head,h);
}

‘肆’ C语言二级考试循环链表是循环队列的链式存储结构

循环队列本身是一种顺序存储结构,而循环列表是一种链式存储结构。两者之间是平级关系。

线性链表是线性表的链式存储结构,包括单链表,双链表,循环链表等。

队列的顺序存储结构一般采用循环队列的形式。

循环队列的操作是按数组取摸运算的,所以是顺序存储,而循环链表本身就是收尾相连的,所以循环链表不是循环队列,两种不同的存储结构,虽然实现的功能是一样的,实现循环两种方式 顺序存储就是循环队列,链式存储就是循环链表。

(4)循环链表探索存储扩展阅读:

1、比顺序存储结构的存储密度小(链式存储结构中每个结点都由数据域与指针域两部分组成,相比顺序存储结构增加了存储空间)。

2、逻辑上相邻的节点物理上不必相邻。

3、插入、删除灵活 (不必移动节点,只要改变节点中的指针)。

4、查找节点时链式存储要比顺序存储慢。

5、每个节点是由数据域和指针域组成。

6、由于簇是随机分配的,这也使数据删除后覆盖几率降低,恢复可能提高。

‘伍’ 循环链表和双向链表的区别是是什么

1、最后一个结点指针指向不同

在建立一个循环链表时,必须使其最后一个结点的指针指向表头结点,而不是像双向链表那样置为NULL。此种情况还用于在最后一个结点后插入一个新的结点。

2、判断链域值不同

在判断是否到表尾时,是判断该结点链域的值是否是表头结点,当链域值等于表头指针时,说明已到表尾。而非像单链表那样判断链域值是否为NULL。

3、访问方式:

循环链表:可以从任何一个结点开始,顺序向后访问到达任意结点

双向链表:可以从任何结点开始任意向前向后双向访问

4、操作:

循环链表:只能在当前结点后插入和删除

双链表:可以在当前结点前面或者后面插入,可以删除前趋和后继(包括结点自己)

5、存储:
循环链表存储密度大于双链表

(5)循环链表探索存储扩展阅读

线性表的链式存储表示的特点是用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素与其直接后继数据元素 之间的逻辑关系,对数据元素 来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。

由这两部分信息组成一个"结点"(如概述旁的图所示),表示线性表中一个数据元素。线性表的链式存储表示,有一个缺点就是要找一个数,必须要从头开始找起,十分麻烦。

根据情况,也可以自己设计链表的其它扩展。但是一般不会在边上附加数据,因为链表的点和边基本上是一一对应的(除了第一个或者最后一个节点,但是也不会产生特殊情况)。不过有一个特例是如果链表支持在链表的一段中把前和后指针反向,反向标记加在边上可能会更方便。

对于非线性的链表,可以参见相关的其他数据结构,例如树、图。另外有一种基于多个线性链表的数据结构:跳表,插入、删除和查找等基本操作的速度可以达到O(nlogn),和平衡二叉树一样。

其中存储数据元素信息的域称作数据域(设域名为data),存储直接后继存储位置的域称为指针域(设域名为next)。指针域中存储的信息又称做指针或链。

由分别表示,,…,的N 个结点依次相链构成的链表,称为线性表的链式存储表示,由于此类链表的每个结点中只包含一个指针域,故又称单链表或线性链表。

‘陆’ 循环链表的存储空间是连续的,为什么错

循环链表是由单链表的最后一个结点指针不指向null,而是指向头结点而成。因此我们分析单链表的存储结构。
单链表是通过一组任意的存储单元存储线性表中的元素的。 这是单链表的定义。单链表的存储单元是任意的!! 没有说要连续。

连续的只有顺序表!顺序表!顺序表!
顺序表是用一组地址连续!!的存储单元,依次!!存储线性表中的数据元素。

而循环链表 它的定义前面已经说了,只是最后一个结点不为null(空),而是指向链表的头结点哦。
循环链表也是链表,链表的存储空间不一定连续的。
但是顺序表是一定连续的存储空间哦。

‘柒’ 线性表的双向循环链表存储结构及其上的基本操作,至少要求实现10个以上的基本操作

/*
下面有结果
*/
# include <stdio.h>
# include <stdlib.h>
# define TRUE 1
# define FALSE 0
# define OK 1
# define ERROR 0
typedef int Status;
typedef int ElemType;
typedef struct DuLNode
{
ElemType data;
DuLNode * prior,* next;
}DuLNode,* DuLinkList;
Status equal(ElemType c1, ElemType c2)
{
if (c1 == c2)
{
return TRUE;
}
else
{
return FALSE;
}
}
int comp(ElemType a, ElemType b)
{
if (a == b)
{
return 0;
}
else
{
return (a-b)/abs(a-b);
}
}
void print(ElemType c)
{
printf("%d ",c);
}
void print2(ElemType c)
{
printf("%c ",c);
}
void print1(ElemType * c)
{
printf("%d ",* c);
}
//产生空的双向循环链表L,
void InitList(DuLinkList * L)
{
* L = (DuLinkList)malloc(sizeof(DuLNode));
if (* L)
{
(* L)->next = (* L)->prior = * L;
}
else
{
exit(0);
}
}
//销毁双向循环链表L
void DestroyList(DuLinkList * L)
{
DuLinkList q,p = (* L)->next;
while (p != (* L))
{
q = p->next;
free(p);
p = q;
}
free(* L);
(* L) = NULL;
}
//将L重置为空表
void ClearList(DuLinkList L)
{
DuLinkList q,p = L->next;
while (p != L)
{
q = p->next;
free(p);
p = q;
}
L->next = L->prior = L;
}
//线性表L已经存在,如果L为空表,则返回TRUE,否则返回FALSE
Status ListEmpty(DuLinkList L)
{
if (L->next==L && L->prior==L)
{
return TRUE;
}
else
{
return FALSE;
}
}
//L已经存在,返回L中数据元素的个数
int ListLength(DuLinkList L)
{
int i = 0;
DuLinkList p = L->next;
while (p != L)
{
i++;
p = p->next;
}
return i;
}
//当第i个元素存在时,将其值赋给e,并返回OK,否则返回FALSE
Status GetElem(DuLinkList L,int i,ElemType * e)
{
int j = 1;
DuLinkList p = L->next;
while (p!=L && j<i)
{
p = p->next;
j++;
}
if (p==L || j>i)
{
return ERROR;
}
* e = p->data;
return OK;
}

//返回L中第一个与e满足关系compare的数据元素的位序
//如果这样的元素不存在,则返回值为0
int LocateElem(DuLinkList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
int i = 0;
DuLinkList p = L->next;
while (p != L)
{
i++;
if (compare(p->data,e))
{
return i;
}
p = p->next;
}
return 0;
}
//如果cur_e是L的数据元素,并且不是第一个,则用pre_e返回它的前驱
Status PriorElem(DuLinkList L,ElemType cur_e,ElemType * pre_e)
{
DuLinkList p = L->next->next;//p指向第二个元素
while (p != L)
{
if (p->data == cur_e)
{
* pre_e = p->prior->data;
return TRUE;
}
p = p->next;
}
return FALSE;
}
//如果cur_e是L的数据元素,并且不是最后一个,
//则用next_e返回它的后继元素,否则操作失败,next_e没有定义
Status NextElem(DuLinkList L,ElemType cur_e,ElemType * next_e)
{
DuLinkList p = L->next->next;
while (p != L)
{
if (p->prior->data == cur_e)
{
* next_e = p->data;
return TRUE;
}
p = p->next;
}
return FALSE;
}
//返回双向链表L的第i个元素的地址,如果i = 0,则返回头结点的地址
//如果第i个元素不存在,则返回NULL
DuLinkList GetElemP(DuLinkList L,int i)
{
int j;
DuLinkList p = L;
if (i<0 || i>ListLength(L))
{
return NULL;
}
for (j=1; j<=i; ++j)
{
p = p->next;
}
return p;
}
//在带头结点的双链循环线性表L中的第i个位置之前插入元素e,
Status ListInsert(DuLinkList L,int i,ElemType e)
{
DuLinkList p,s;
if (i<1 || i>ListLength(L)+1)
{
return ERROR;
}
p = GetElemP(L,i-1);
if (!p)
{
return ERROR;
}
s = (DuLinkList)malloc(sizeof(DuLNode));
if (!s)
{
return 0;
}
s->data = e;
s->prior = p;
s->next = p->next;
p->next->prior = s;
p->next = s;
return OK;
}
//在带头结点的双链循环线性表L中,删除其第i个元素,
Status ListDelete(DuLinkList L,int i,ElemType * e)
{
DuLinkList p;
if (i<1)
{
return ERROR;
}
p = GetElemP(L,i);
if (!p)
{
return ERROR;
}
* e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
}
//由双链循环线性表L的头结点出发,正序对每个元素调用函数visit
//主要是正序
void ListTraverse(DuLinkList L,void(*visit)(ElemType))
{
DuLinkList p = L->next;//p指向头结点
while (p != L)
{
visit(p->data);
p = p->next;
}
printf("\n");
}
//从双链循环线性表L的头结点出发,逆序对每个数据元素调用函数visit
void ListTraverseBack(DuLinkList L,void(*visit)(ElemType))
{
DuLinkList p = L->prior;
while (p != L)
{
visit(p->data);
p = p->prior;
}
printf("\n");
}
int main(void)
{
DuLinkList L;
int i,n;
Status j;
ElemType e;
InitList(&L);
for (i=1; i<=5; ++i)
{
ListInsert(L,i,i);
}
printf("正序输出链表:");
ListTraverse(L,print);
printf("逆序输出链表:");
ListTraverseBack(L,print);
n = 2;
ListDelete(L,n,&e);
printf("删除第%d个结点,其值是%d,其余的结点是(正序输出):\n",n,e);
ListTraverse(L,print);
printf("链表的元素个数为%d\n",ListLength(L));
printf("链表是否空:%d(1:空 0:非空)\n",ListEmpty(L));
ClearList(L);
printf("清空后,链表空吗:%d(1:空 0:非空)\n",ListEmpty(L));
printf("重新插入5个元素:\n然后正序遍历:");
for (i=1; i<=5; ++i)
{
ListInsert(L,i,i);
}
ListTraverse(L,print);//正序输出
n = 3;
j = GetElem(L,n,&e);
if (j)
{
printf("链表的第%d个元素的值为%d\n",n,e);
}
else
{
printf("不存在第%d个元素\n",n);
}
n = 4;
i = LocateElem(L,n,equal);
if (i)
{
printf("L中第%d个元素是%d\n",i,n);
}
else
{
printf("L中没有元素%d\n",n);
}
j = PriorElem(L,n,&e);
if (j)
{
printf("%d的前驱是%d\n",n,e);
}
else
{
printf("%d没有前驱\n");
}
j = NextElem(L,n,&e);
if (j)
{
printf("%d的后继是%d\n",n,e);
}
else
{
printf("%d没有后继元素\n");
}
DestroyList(&L);
return 0;
}
/*
在vc++6.0中的输出结果:
------------------------
正序输出链表:1 2 3 4 5
逆序输出链表:5 4 3 2 1
删除第2个结点,其值是2,其余的结点是(正序输出):
1 3 4 5
链表的元素个数为4
链表是否空:0(1:空 0:非空)
清空后,链表空吗:1(1:空 0:非空)
重新插入5个元素:
然后正序遍历:1 2 3 4 5
链表的第3个元素的值为3
L中第4个元素是4
4的前驱是3
4的后继是5
Press any key to continue
------------------------------
*/

‘捌’ 双向循环链表的主要优点

双向链表的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

单链表的缺点是只能往前,不能后退,虽然有循环单链表,但后退的成本还是很高的,需要跑一圈。在这个时候呢,双向链表就应运而生了,再加上循环即双向循环链表就更加不错了。所谓双向链表只不过是添加了一个指向前驱结点的指针,双向循环链表是将最后一个结点的后继指针指向头结点。

(8)循环链表探索存储扩展阅读:

循环链表是一种链式存储结构,它的最后一个结点指向头结点,形成一个环。因此,从循环链表中的任何一个结点出发都能找到任何其他结点。循环链表的操作和单链表的操作基本一致,差别仅仅在于算法中的循环条件有所不同。

单向链表(单链表)其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始。 通过指针连接起来,但是只能单向遍历的内存块。由于它是单向的,或者说不可逆的,所以我们可以把它比作人生:小学->中学->大学->工作->养老。

‘玖’ 循环链表的主要优点是

循环链表的特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。

(1)单循环链表——在单链表中,将终端结点的指针域NULL改为指向表头结点或开始结点即可。

(2)多重链的循环链表——将表中结点链在多个环上。

注意:

①循环链表中没有NULL指针。涉及遍历操作时,其终止条件就不再是像非循环链表那样判别p或p->next是否为空,而是判别它们是否等于某一指定指针,如头指针或尾指针等。

②在单链表中,从一已知结点出发,只能访问到该结点及其后续结点,无法找到该结点之前的其它结点。而在单循环链表中,从任一结点出发都可访问到表中所有结点,这一优点使某些运算在单循环链表上易于实现。

‘拾’ 什么是链表 单链表;双向链表;循环链表 各是怎么进行存储和操作的

C语言中,链表的实质就是一种结构体类型。结构体清楚吧?结构体就是按一定方式组合的类型的集体,组成的一种类型。
而链表,实际上就是在这个结构体中,有这样一种变量,它们是指针,指向跟自己同种类型的结构体。当我们把a中的指针指向b,b中的指针指向c,...,就构成了一个单向的链表。
至于双向链表,是类似的,只不过一个节点同时指向了它前后的两个节点,适宜双向查找。
循环链表,与一般链表的区别,就是最后一个节点,又反过来指向了第一个节点。