带头结点的并具有头尾指针的单循环链表

带头结点的并具有头尾指针的单循环链表
带头结点的并具有头尾指针的单循环链表

长治学院

课程设计任务书

课程名称:数据结构课程设计

设计题目:带头结点的并具有头尾指针的单循环链表

系别:计算机系

专业:网络工程

学生姓名: 王鲁俊学号: 07407320 起止日期: 2008年 11月08 日~ 2008年12月18 日指导教师:孙俊杰

长治学院

第一

需求

分析

------

------

------

------

------

------

------

------

------

------

------

------

-3 第二章开发过程-------------------------------------------------------------------------3

2.1系统目标----------------------------------------------------------------------3

2.2设计出友好的界面---------------------------------------------------- ---3 2.3实现

基本功能----------------------------------------------------------------3

2.5功能划分----------------------------------------------------------------------3

第三章系统设计--------------------------------------------------4

3.1系统设计方法-------------------------------------------4

3.2数据结构设计-------------------------------------------4

3.3数据结构设计概述---------------------------------------4

3.4数据实体类型-------------------------------------------4

3.5流程图-------------------------------------------------5

3.6程序中的源代码-----------------------------------------5

第四章附录-----------------------------------------------------13

第一章需求分析

1.编写带头结点头尾指针的单循环链表,并实现功能如下:

1.编写该单循环链表的环境

2.保存数据

3.建立密码,密码修改

4.单循环链表的位置查找.插入.删除.排序等操作

第二章开发过程

2.1系统目标

长治学院

本系统的目标是实现单向链表的各种操作,方便用户对数据的各种操作。

2.2 设计友好界面

设计友好界面,实现界面人为化,使系统简单,使用户能舒心.方便的实现自己的操作

2.3实现一些基本功能

在单循环链表的某一位置的前面或后面插入某一数据,删除单向链表中的某一结点,返回某一结点的位置,实现升序排序,降序排序的算法,至零,清空等各种算法。

2.4功能划分

1.友好界面

2.密码编写

3.修改密码

4.数据存盘

5.单循环链表的各种操作

第三章系统设计

3.1系统设计的方法

系统设计是把需求转化为软件系统的最重要的环节。系统设计的优劣在根本上决定了软件系统的质量。系统设计的五个方面的要求:体系结构设计,模块设计,数据结构设计与算法设计,用户界面设计。

3.2数据结构设计

3.2.1数据结构设计概述

数据结构是一门研究非数值计算的程序设计问题中计算机的操作对象以及他们之间的关系和操作等的学科。“数据结构”的研究不仅涉及到计算机硬件的研究范围,而且和计算机软件的研究有着更密切的关系,无论是编译程序还是操作系统,都涉及到数据单元在存储器中的分配问题。良好的数据结构设计,可以提高数据信息的存储效率,保证数据信息的完整性和一致性。同时,一个合理的数据结构有利于程序的实现。这里选用TURBOC2作为编译环境。

3.2.2数据实体类型

节点定义:每个节点包括数据域data,指针域next。

链表定义:链表S,头指针Head,尾指针tail

3.4 界面中单链表的部分算法:

3.4.1

void gaimi()

长治学院

{

int i=0;

char ch,a[6],b[6];

printf(" 请输入原始密码:");

ch=getchar();

gets(a);

while((yanzheng1(a))!=6)

{

printf(" 请输入原始密码:");

gets(a);

}

while(1)

{

printf(" 输入新设密码:");

gets(a);

printf(" 再次输入新设密码:");

gets(b);

while(a[i]==b[i])

i++;

if(i==5)break;

else i=0;

}

xiugai(a);

}

void xiugai(char *x)

{

FILE *fp;

fp=fopen("mima","wb");

fputs(x,fp);

printf("\t****************************************************\n");

printf("\t***************************************************\n"); printf("\t******************密码修改成功!!********* *********\n");

printf(“\*************任意键继续操作*************\n");

printf("\t***************************************************\n");

getch();

fclose(fp);

}

int yanzheng1(char *x)

{

FILE *fp;

int i=0;

char ch;

if((fp=fopen("mima","r"))==NULL)

{

printf("无密码.\n");

}

ch=fgetc(fp);

while(ch!=EOF)

{

if(x[i]==ch)

i++;

ch=fgetc(fp);

}

if(i==5)

{

printf(" 密码正确.\n"); }

else

{

printf(" 密码错误.\n"); }

fclose(fp);

return(i);

}

void Insbefore(LNodelist *s)

{/*在链表中一个结点前插入一个数据5*/

长治学院

LNode *p,*q,*t; int x,y,i;

printf("输入该链表中一个结点的值:\n");

scanf("%d",&x);

p=s->head;t=p->next;

if(s->head->data==x)

{

printf("输入要插入的数据:\n");

scanf("%d",&y);

q=(LNode *)malloc(sizeof(LNode));

q->data=y;

q->next=s->head;

s->tail->next=q;

s->head=q;

}

else{

while(p->next->data!=x&&p->next!=s->head)

{p=p->next;t=t->next;}

if(p->next->data!=x&&p->next==s->head) printf("数据插入位不存在!\n"); else{

printf("输入要插入的数据:\n");

scanf("%d",&y);

q=(LNode *)malloc(sizeof(LNode));

q->data=y;

q->next=t;

p->next=q;

printf("输出插入数据后的链表:\n");

Printlink(s);

}

}

printf("是否储存数据.(0:否1:是)\n");

scanf("%d",&i);

if(i==1)

chucun(s);

else printf("数据没有存储!\n");

}

void InsAfter(LNodelist *s)

{ /*在链表中的一个结点后插入一个数据6*/

LNode *p,*q,*t; int x,y,i;

printf("输入该链表中的一个结点的值:\n");

scanf("%d",&x);

p=s->head;t=p->next;

while(p->data!=x&&p->next!=s->head)

{p=p->next;t=t->next;}

if(p->data!=x&&p->next==s->head){printf("输入的数据不存在!\n");} else

{ printf("输入要插入的数据:\n");

scanf("%d",&y);

q=(LNode *)malloc(sizeof(LNode));

q->data=y;

q->next=t;

p->next=q;

printf("输出插入数据后的链表:\n");

Printlink(s);

}

printf("是否储存数据.(0:否1:是)\n");

scanf("%d",&i);

if(i==1)

chucun(s);

else printf("数据没有存储!\n");

}

void Setcurelem(LNodelist *s)

{ /*链表中的一个结点用另一个数据替换7*/

LNode *p,*q,*t; int x,y,i;

printf("输入链表中被替换的数据:\n");

scanf("%d",&x);

p=s->head;t=p->next;

长治学院

while(p->data!=x&&p->next!=s->head)

{p=p->next;t=t->next;}

if(p->data!=x){printf(" 被更新的数据不存在!");} else

{ printf("输入新数据:\n");

scanf("%d",&y);

p->data=y;

printf("输出被替换后的单循环链表:\n");

Printlink(s);

printf("是否储存数据.(0:否1:是)\n");

scanf("%d",&i);

if(i==1)

chucun(s);

else printf("数据没有存储!\n");

}

}

void Getcurelem(LNodelist *s)

{ /*反回链表中的一个结点8*/

LNode *p; int x;

printf("输入链表一个结点值:\n");

scanf("%d",&x);

p=s->head;

while(p->data!=x&&p->next!=s->head)

p=p->next;

if(p->data!=x){printf("要输出的结点不存在!");} else

{ printf("输出该结点的值:\n");

printf("%d",p->data);

}

}

void listempt(LNodelist *s)

{ /*判链空9*/

LNode *p;int i=0;

p=s->head;

while(p->next!=s->head&&p!=NULL)

{ p=p->next;i++;}

if(i==0)printf("链表为空!");

else printf("链表不为空!");

}

void lengthlist(LNodelist *s)

{ /*输出单循环链表中元素的个数10*/

LNode *p; int i=0;

p=s->head;

if(p==NULL) {printf("该链表为空链表!");}

else

{while(p->next!=s->head)

{p=p->next;i++;}

printf("输出链表中元素的个数:\n");

printf("%d",i);

}

}

void gethead(LNodelist *s)

{ /*输出第一个结点的位置11*/

printf("输出第一个结点的位置:\n");

printf("%d",s->head->data);

}

void Nextpos(LNodelist *s)

{ /*在链表中的一个结点直接后继位置14*/

LNode *p,*q; int x,y;

printf("输入链表中一个结点值:\n");

scanf("%d",&x);

p=s->head;

while(p->data!=x&&p->next!=s->head)

p=p->next;

if(p->data!=x){printf("该结点不存在!");exit(0);}

长治学院

else

{ printf("输出该结点的后继位置:\n");

printf("%d",p->next->data);

}

}

void Locatepos(LNodelist *s)

{ /*输出链表中第i个结点的位置15*/

LNode *p,*q; int i,j=1;

printf("输入链表任意一结点的下标值:");

scanf("%d",&i);

p=s->head;

while(j!=i&&p!=s->tail)

{ p=p->next;j++;}

if(p==s->tail)

{if(j==i)

{ printf(" 输出该结点的值:\n");

printf("%d",p->data);

}

else printf("输入位置有误!\n");

}

else

{ printf("输出该结点的值:\n");

printf("%d",p->data);

}

}

void paixu(LNodelist *s)

{/*单循环链表排序16*/

LNode *p,*q,*t;int i;

p=s->head;

printf("请选择操作号:\n1:从大到小排序.\n2:从小到大排序.\n"); scanf("%d",&i);

switch(i)

{

case 1: printf("单循环链表从大到小排序:\n"); while(p->next!=s->head)

{

q=p->next;

while(q!=s->head)

{

if(p->datadata)

{

t=p->data;p->data=q->data;q->data=t;

}

else q=q->next;

}

p=p->next;

}

printf("从大到小输出单循环链表:\n");

Printlink(s);

break;

case 2:

while(p->next!=s->head)

{

q=p->next;

while(q!=s->head)

{

if(p->data>q->data)

{

t=p->data;p->data=q->data;q->data=t;

}

else q=q->next;

}

p=p->next;

}

printf("从小到大输出单循环链表:\n");

Printlink(s);

break;

长治学院

default: printf("输入的操作号不正确!\n");

}

printf("是否储存数据.(0:否1:是)\n");

scanf("%d",&i);

if(i==1)

chucun(s);

else printf("数据没有存储!\n");

}

int chucun(LNodelist *s)

{ /*存储数据*/

FILE *fp=NULL;

char filename[10],ch;

LNode *p=s->head;

if(s==NULL)

{printf("链表不存在,请建立链表:");

getch();

return 0;

}

printf("输入文件名:");

scanf("%s",filename);

while((fp=fopen(filename,"r"))!=NULL)

{ fclose(fp);

printf("链表已存在,请从新建立链表\n"); ch=getchar();

printf("请输入文件名:");

scanf("%s",filename);

}

fp=fopen(filename,"w");

while(p->next!=s->head)

{

fwrite(p,sizeof(LNode),1,fp);

p=p->next;

}

fwrite(p,sizeof(LNode),1,fp);

fclose(fp);

printf("存储成功.\n");

return(1);

}

int openfile(LNodelist *s)

{FILE *fp;

char filename[10];

LNode *p=NULL,*q=NULL;

p=s->head;

printf("请输入要打开的文件名:");

scanf("%s",filename);

if((fp=fopen(filename,"r"))==NULL)

{

printf("文件不存在!请从新输入文件名!\n");

getch();return 0;

}fread(p,sizeof(struct node),1,fp);

while(!feof(fp))

{ q=(LNode *)malloc(sizeof(LNode));

if(fread(q,sizeof(struct node),1,fp)!=1)break;

q->next=p->next;p->next=q;p=q;

}p->next=s->head;

fclose(fp);Printlink(s); return(1);

}

参考文献:

[1] 《C程序设计(第三版)》,谭浩强,清华大学出版社,2005.

[2] 《数据结构(C语言版)》,严蔚敏,清华大学出版社,2007。

长治学院

c语言链表解析

c语言链表解析 编程思想: 链表由一系列不必在内存中相连的结构组成。每一个结构均含有表元素和指向包含该元素后继元的结构指针。我们称之为next指针。最后一个单元的next指针指向NULL;该值由C定义并且不能与其它指针混淆。ANSI C规定NULL为零。 指针变量是包含存储另外某个数据的地址的变量。因此,如果P被声明为指向一个结构的指针,那么存储在P中的值就被解释为内存中的一个位置,在该位置能够找到一个结构。该结构的一个域可以通过P->FileName访问,其中FileName是我们要考察的域的名字。如图1所示,这个表含有五个结构,恰好在内存中分配给它们的位置分别是1000,800,712,992和692。第一个结构的指针含有值800,它提供了第二个结构所在的位置。其余每个结构也都有一个指针用于类似的目的。当然,为了访问该表,我们需要知道在哪里能够找到第一个单元。 图1 为了执行打印表PrinList(L)或查找表Find(L,key),只要将一个指针传递到该表的第一个元素,然后用一些Next指针穿越该表即可。 删除命令可以通过修改一个指针来实现。图2给出在原表中删除第三个元素的结果。 图2 插入命令需要使用一次malloc调用从系统得到一个新单元并在此后执行两次指针调整。想法通过图3给出,其中虚线表示原来的指针。 图3

程序设计: 上面的描述实际上足以使每一部分都能正常工作,但还是有几处地方可能会出问题: 1、并不存在从所给定义出发在表的前面插入元素的真正显性的方法。 2、从表的前面实行删除是一个特殊情况,因为它改变了表的起始端;编程的疏忽将会造成表的丢失。 3、在执行删除命令时,要求我们记住被删除元素前面的表元。 事实上,稍作一个简单的变化就能够解决所有这三个问题。做一个标志节点——表头(header)。图4表示一个带头头结点的链表。 图4 为了避免删除操作相关的一些问题,我们需要编写一个FindPrevious函数,它将返回我们要删除的表元的前驱元的位置。如果我们使用表头,那么当删除表的第一个元素时,FindPrevious将返回表头的位置。 代码实现: 按照C的约定,作为类型的List(表)和Position(位置)以及函数的原型都列在所谓的.h 头文件中。具体的Node(节点)声明则在.c文件中。 代码1、链表的类型声明 #ifndef _List_H struct Node; typedef struct Node *PtrToNode; typedef PtrToNode List; typedef PtrToNode Posotion; List MakeEmpty(List L); int IsEmpty(List L); int IsLast(Position P, List L); Position Find(ElementType X, List L); void Delete(ElementType X, List L); Position FindPrevious(ElementType X, List L); void Insert(ElementType X, List L, Position P); void DeleteList(List L); struct Node { ElementType Elment; Position Next; } 代码2、测试一个链表是否是空表的函数。(头结点的Next指向NULL时为空链表)

C++链表的创建与操作

C++链表的创建与操作 我们知道,数组式计算机根据事先定义好的数组类型与长度自动为其分配一连续的存储单元,相同数组的位置和距离都是固定的,也就是说,任何一个数组元素的地址都可一个简单的公式计算出来,因此这种结构可以有效的对数组元素进行随机访问。但若对数组元素进行插入和删除操作,则会引起大量数据的移动,从而使简单的数据处理变得非常复杂,低效。 为了能有效地解决这些问题,一种称为“链表”的数据结构得到了广泛应用。 1.链表概述 链表是一种动态数据结构,他的特点是用一组任意的存储单元(可以是连续的,也可以是不连续的)存放数据元素。 链表中每一个元素成为“结点”,每一个结点都是由数据域和指针域组成的,每个结点中的指针域指向下一个结点。Head是“头指针”,表示链表的开始,用来指向第一个结点,而最后一个指针的指针域为NULL(空地址),表示链表的结束。 可以看出链表结构必须利用指针才能实现,即一个结点中必须包含一个指针变量,用来存放下一个结点的地址。 实际上,链表中的每个结点可以用若干个数据和若干个指针。结点中只有一个指针的链表称为单链表,这是最简单的链表结构。 再c++中实现一个单链表结构比较简单。例如,可定义单链表结构的最简单形式如下 struct Node{ int Data; Node *next; }; 这里用到了结构体类型。其中,*next是指针域,用来指向该结点的下一个结点;Data是一个整形变量,用来存放结点中的数据。当然,Data可以是任何数据类型,包括结构体类型或类类型。 在此基础上,我们在定义一个链表类list,其中包含链表结点的插入,删除,输出等功能的成员函数。class list{ Node *head; public: list(){head=NULL;} void insertlist(int aDate,int bDate); //链表结点的插入 void Deletelist(int aDate); //链表结点的删除 void Outputlist(); //链表结点的输出 Node*Gethead(){return head;} }; 2.链表结点的访问 由于链表中的各个结点是由指针链接在一起的,其存储单元文笔是连续的,因此,对其中任意结点的地址无法向数组一样,用一个简单的公式计算出来,进行随机访问。只能从链表的头指针(即head)开始,用一个指针p先指向第一个结点,然后根据结点p找到下一个结点。以此类推,直至找到所要访问的结点或到最后一个结点(指针为空)为止。 下面我们给出上述链表的输出函数; void list::Outputlist(){ Node *current = head; while(current != NULL){ cout << current->Data << " "; current = current->next;

指针测试题

C++测试(指针) 学号姓名成绩 一、选择题(每题1.5分,共24分) 1.语句int a=10,*point=&a;其值不为地址。 A. point B. &a C. &point D. *point 2.若p为指针变量,y为变量,则y = *p++;的含义是 A.y=*p;p++ B.y=(*p)++ C.y=p;p++ D.p++;y=*p 3.语句char str[]=?visual C++?;char *p=str;则p的值为 A. ?visual C++? B.str的首地址 C. \n D.?v? 4.设有说明语句char *s[]={?student?,?Teacher?,?Father?,?Month?}, *ps=s[2];执行语句:cout<<*s[1]<<’,’<next=&b; D.(*p).next=q; 9.下面正确的语句是 A. int a[3][4],(*p)[4]; p=a; B. int a[3][4],*p[4]; p=a; C. int a[3][4],*p; p=a; D. int a[3][4],**p;*p=a; 10.下面不正确的语句是 A.float *p;p=new float[3]; B. int *p;p=new int[3](1,2,3); C. float *p;p=new float(3); D. int (*p)[4];p=new int[3][4]; 11.设有函数定义:int f1(void){return 100,150;}调用函数f1()时, A.函数返回值100 B. 函数返回值150 C. 函数返回二个值100和150 D. 语句return 100,150;语法错. 12.设有语句:int fun(char *,int &);char str[100];int k;则对函数fun的正确的调用形式是 A.fun(str,&k) B.fun(str,k) C.fun(str[100],k) D.fun(str, &k) 13.数组作为函数的形参时,把数组名作为实参,传递给函数的是 A.该数组的首地址 B. 该数组的元素个数 C. 该数组中的各元素值 D. 该数组的大小 14.执行以下语句序列:则 enum {Sun,Mon,Tue,Wed,Thu,Fri,Sat}c1,c2; //A

《数据结构》实验报告 设计循环单链表

《数据结构》实验报告 1、实验名称:设计循环单链表 2、实验日期: 2013-3-26 3、基本要求: 1)循环单链表的操作,包括初始化、求数据元素个数、插入、删除、取数据元素; 2)设计一个测试主函数实际运行验证所设计循环单链表的正确性。 4、测试数据: 依次输入1,2,3,4,5,6,7,8,9,10,删除5,再依次输出数据元素。 5、算法思想或算法步骤: 主函数主要是在带头结点的循环单链表中删除第i个结点,其主要思想是在循环单链表中寻找到第i-1个结点并由指针p指示,然后让指针s指向a[i]结点,并把数据元素a[i]的值赋给x,最后把a[i]结点脱链,并动态释放a[i]结点的存储空间。 6、模块划分: 1)头文件LinList.h。头文件LinList.h中包括:结点结构体定义、初始化操作、求当前数据个数、插入一个结点操作、删除一个结点操作以及取一个数据元素操作; 2)实现文件dlb.cpp。包含主函数void main(void),其功能是测试所设计的循环单链表的正确性。

7、数据结构: 链表中的结点的结构体定义如下: typedef struct Node { DataType data; struct Node *next; }SLNode; 8、源程序: 源程序存放在两个文件中,即头文件LinList.h和实现文件dlb.cpp。//头文件LinList.h typedef struct Node { DataType data; struct Node *next; }SLNode; void ListInitiate(SLNode **head) //初始化 { *head=(SLNode *)malloc(sizeof(SLNode)); //申请头结点,由head指示其地址 (*head)->next=*head; }

北京邮电大学 数据结构 实验一 带头结点的单链表构造

数据结构实验报告 实验名称:实验1——单链表的构造 学生姓名:XXXXNB 班级:XXXX 班内序号: 学号:XXXX 日期:XXXXX 1.实验要求 根据线性表的抽象数据类型的定义,完成带头结点的单链表的基本功能。 单链表的基本功能: 1、构造:使用头插法、尾插法两种方法 2、插入:要求建立的链表按照关键字从小到大有序 3、删除 4、查找 5、获取链表长度 6、销毁 7、其他:可自行定义 编写测试main()函数测试线性表的正确性。 2.程序分 编程完成单链表的一般性功能如单链表的构造:使用头插法、尾插法两种方法插入:要求建立的链表按照关键字从小到大有序,删除,查找,获取链表长度,销毁用《数据结构》中的相关思想结合C++语言基本知识编写一个单链表结构。本程序为使用方便,几乎不用特殊的命令,只需按提示输入即可,适合更多的用户使用。 2.1 存储结构 单链表的存储结构:

2.2 关键算法分析 1.头插法 自然语言描述:a.在堆中建立新结点 b.将a[i]写入到新结点的数据域 c.修改新结点的指针域 d.修改头结点的指针域,将新结点加入链表中 //在构建之初为了链表的美观性构造,进行了排序 代码描述: //头插法构造函数 template LinkList::LinkList(T a[], int n) { for (int i = n - 1; i >= 1; i--)//冒泡排序,对数组进行从小到大排序{ for (int j = 0; j < i; j++) { if (a[j]>a[j + 1]) { T t = a[j + 1]; a[j + 1] = a[j]; a[j] = t; } }

C程序设计(链表)习题与答案

一、单选题 1、链表不具有的特点是()。 A.不必事先估计存储空间 B.插入、删除不需要移动元素 C.可随机访问任一元素 D.所需空间与线性表长度成正比 正确答案:C 2、链接存储的存储结构所占存储空间()。 A.分两部分,一部分存放结点值,另一部分存放结点所占单元数 B.只有一部分,存放结点值 C.分两部分,一部分存放结点值,另一部分存放表示结点间关系的指针 D.只有一部分,存储表示结点间关系的指针 正确答案:C 3、链表是一种采用()存储结构存储的线性表。 A.网状 B.星式 C.链式 D.顺序 正确答案:C 4、有以下结构体说明和变量的定义,且指针p指向变量a,指针q指向变量b,则不能把结点b连接到结点a之后的语句是()。 struct node { char data; struct node *next; } a,b,*p=&a,*q=&b;

A.(*p).next=q; B.p.next=&b; C.a.next=q; D.p->next=&b; 正确答案:B 5、下面程序执行后的输出结果是()。 #include #include struct NODE { int num; struct NODE *next; }; int main() { struct NODE *p,*q,*r; p=(struct NODE*)malloc(sizeof(struct NODE)); q=(struct NODE*)malloc(sizeof(struct NODE)); r=(struct NODE*)malloc(sizeof(struct NODE)); p->num=10; q->num=20; r->num=30; p->next=q;q->next=r; printf("%d",p->num+q->next->num); return 0; } A.30 B.40 C.10 D.20 正确答案:B 6、下面程序执行后的输出结果是()。 #include struct NODE { i nt num; struct NODE *next; } ;

线性表练习题(答案)

第2章线性表 一选择题 下列程序段的时间复杂度为( C )。 for( int i=1;i<=n;i++) for( int j=1;j<= m; j++) A[i][j] = i*j ; A. O(m2) B. O(n2) C. O(m*n) D. (m+n) 下面关于线性表的叙述中,错误的是哪一个?(B ) A.线性表采用顺序存储,必须占用一片连续的存储单元。 B.线性表采用顺序存储,便于进行插入和删除操作。 C.线性表采用链接存储,不必占用一片连续的存储单元。 D.线性表采用链接存储,便于插入和删除操作。 线性表是具有n个( C )的有限序列(n>0)。 A.表元素B.字符C.数据元素D.数据项 若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用( A )存储方式最节省时间。 A.顺序表B.双链表C.带头结点的双循环链表D.单循环链表 某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用( D )存储方式最节省运算时间。 A.单链表B.仅有头指针的单循环链表 C.双链表D.仅有尾指针的单循环链表 设一个链表最常用的操作是在末尾插入结点和删除尾结点,则选用( D )最节省时间。A. 单链表 B.单循环链表 C. 带尾指针的单循环链表 D.带头结点的双循环链表 若某表最常用的操作是在最后一个结点之后插入一个结点或删除最后一个结点。则采用( D )存储方式最节省运算时间。 A.单链表B.双链表C.单循环链表D.带头结点的双循环链表 链表不具有的特点是( B ) A.插入、删除不需要移动元素B.可随机访问任一元素 C.不必事先估计存储空间D.所需空间与线性长度成正比 下面的叙述不正确的是(B,C ) A.线性表在链式存储时,查找第i个元素的时间同i的值成正比 B. 线性表在链式存储时,查找第i个元素的时间同i的值无关 C. 线性表在顺序存储时,查找第i个元素的时间同i 的值成正比 D. 线性表在顺序存储时,查找第i个元素的时间同i的值无关 若长度为n的线性表采用顺序存储结构,在其第i个位置插入一个新元素的算法的时间复杂度为( C )(1<=i<=n+1)。 A. O(0) B. O(1) C. O(n) D. O(n2) 对于顺序存储的线性表,访问结点和增加、删除结点的时间复杂度为(C )。 A.O(n) O(n) B. O(n) O(1) C. O(1) O(n) D. O(1) O(1) 线性表(a1,a2,…,an)以链接方式存储时,访问第i位置元素的时间复杂性为( C )A.O(i)B.O(1)C.O(n)D.O(i-1) 循环链表H的尾结点P的特点是(A )。 A.P->next=H B.P->next= H->next C.P=H D.P=H->next 完成在双循环链表结点p之后插入s的操作是(D );

单循环链表基本操作

/*1、CreateList( ):创建一个带头结点的空的单循环链表; 2、InsertList( ):输入一组数据,以0表示输入结束, 并依次建立各个元素结点,逐个插入到单循环链表尾 3、DeleteList( ):删除单循环链表的从第i个数据元素开始的m个数据元素,同时释放被删结点空间 4. ListPrint( ):将单向循环链表的数据元素从表头到表尾依次显示 5. DevList( ):将此单循环链表拆分成两个单循环链表,其中一个包含所有的数据元素为偶数的结点, 另一个包含所有的数据元素为奇数的结点.*/ #include #include typedef struct node{ int data; struct node *next; }LNode,*linklist; void createlist(linklist &L) {linklist p=L; p->next=p; } void insertlist(linklist &L) {int x; linklist p=L,q; scanf("%d",&x); while(x!=0) {q=(linklist)malloc(sizeof(LNode)); q->data=x;q->next=NULL; p->next=q; p=q; scanf("%d",&x); } q->next=L; } void printlist(linklist L) {linklist p=L->next ; if(p==L)printf("这是一个空表!\n"); while(p!=L){printf("%2d",p->data);p=p->next;} printf("\n"); } void deletelist(linklist &L,int i,int m) {linklist p=L,q; for(int n=1;nnext; if(p==L)p=p->next; }

约瑟夫环问题单循环链表解法讲解

约瑟夫环问题单循环链表解法 Description 约瑟夫环问题;有N个人围成一个环,从第一个人开始报数,报到M的人退出环,并且由他的M值来代替原有的M值,要求输出离开环的顺序。 Input 第一行有2个数,M和N。(0 第二行有 N 个数,表示每个人的 M 值。 Output 按照样例的格式,输出所有人退出环的顺序。 Sample Input 4 6 5 4 2 3 4 2 Sample Output 4,1,2,3,6,5 Source #include"iostream" #include"cstdio" #include"cstdlib" using namespace std; typedef struct cnode{ int label; int data; struct cnode *next; }cnode; int m,n,i,value,j; cnode *p,*q;

int main( { cin>>m>>n; cnode *clist; q=(cnode *malloc(sizeof(cnode; clist=q; for(i=1;i<=n;i++ { //cin>>value; cin>>value; p=(cnode *malloc(sizeof(cnode; //p=new cnode; p->label=i; p->data=value; p->next=NULL; q->next=p; q=p; if(i==nq->next=clist->next; } p=clist; //cout< label< for(i=1;i<=n;i++ { for(j=1;j { p=p->next; } q=p->next; m=q->data;

变量的指针和指针变量的区别是什么

2变量的指针和指针变量的区别是什么。 答;一个变量的地址指出了变量的存储单元在内存中的具体位置,能对变量进行存取操作。这个变量的地址就是变量的指针。指针是一种具有特殊意义的整型数,指针不能存放在一般的整型变量中,必须存放在专门指针的变量中,这类变量就是指针变量。 3 一维数组元素的引用有哪些方式。 答;下标法、地址法、指针法 4 2维数组列地址有哪些计算方法。 答;1 根据数组元素所在的行计算出行地址,然后把行地址转换成行中首元素的地址,再根据数组元素所在的列计算数组元素的地址。 2 根据2维数组的数组元素在存储空间上按行连续存放的特点,每个数组元素的地址等于2维数组元素的首元素地址加上该数组元素相对于首元素位置的偏移量。 3把2维数组的每一行当作一个一维数组,用一维数组元素地址的计算方法计算相应的2维数组元素的地址。 第9章结构体与共用体 1 什么是链表。其中单向链表具有哪些特点。 答;链表是若干个同样类型的结构通过依次串接方式构成的一种动态数据结构。链表中的每一个结构体数据成为结点,链表可以分成单向链表和双向链表 单向链表的特点;1 链表中的结点数据可以改变的 2 结点占用的内存是动态分配内存和动态释放内存函数。 2 对单向链表的常用操作有哪些。 答;对单向链表的常用操作有建立、显示、插入,删除和查找。 3 什么是共用体。 答;共用体是一个集合体。它的各个成员的数据类型可以是不相同的,所有成员共享同一段存储空间,存储空间的大小取决存储单元最大的成员的数据类型。 4 指向结构体类型变量的指针变量引用形式有哪些。 答;有两种形式;【星号指针变量名】。成员名和指针变量名-大于号成员名。 第10章位运算及编译预处理 1 C提供的编译预处理功能有哪些。如何实现。 答;功能有三种;宏定义、文件包含和条件编译,分别用宏定义命令、文件包含命令、条件编译命令实现。 2 文件包含的基本功能是什么。 答;文件包含处理是一个源文件可以将另一个源文件的全部内容包含到本文件中来,作为本文件的一部分,这可以节省程序设计人员的重复劳动。 【3【在C语言中提供了几种什么样的位运算符。 答;-、小于小于、大于大于、 4 文件包含需要注意哪些问题 答;一个井include命令只能指定一个被包含文件,包含多个文件侧需多个井include命令;文件包含可以嵌套,即一个被包含文件中可以包含另一个被包含的文件;在井include命令中,文件名可以用双引号或尖括号括起来。 第11章文件 1 文件的结束标志有哪些。 答;每个文件都有一个结束标志。当文件的位置指针移到文件的结束标志处时,表示文件结束。如何测试文件是否结束,常有2种方法 1 ASCII码文件的结束标志用【-1】表示。

C语言链表专题复习

链表专题复习 数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了灵活性。但数组也同样存在一些弊病。如数组的大小在定义时要事先规定,不能在程序中进行调整,这样一来,在程序设计中针对不同问题有时需要3 0个元素大小的数组,有时需要5 0个数组元素的大小,难于统一。我们只能够根据可能的最大需求来定义数组,常常会造成一定存储空间的浪费。 我们希望构造动态的数组,随时可以调整数组的大小,以满足不同问题的需要。链表就是我们需要的动态数组。它是在程序的执行过程中根据需要有数据存储就向系统要求申请存储空间,决不构成对存储区的浪费。 链表是一种复杂的数据结构,其数据之间的相互关系使链表分成三种:单链表、循环链表、双向链表,下面只介绍单向链表。 7.4.1 单链表 图7 - 3是单链表的结构。 单链表有一个头节点h e a d,指向链表在内存的首地址。链表中的每一个节点的数据类型为结构体类型,节点有两个成员:整型成员(实际需要保存的数据)和指向下一个结构体类型节点的指针即下一个节点的地址(事实上,此单链表是用于存放整型数据的动态数组)。链表按此结构对各节点的访问需从链表的头找起,后续节点的地址由当前节点给出。无论在表中访问那一个节点,都需要从链表的头开始,顺序向后查找。链表的尾节点由于无后续节点,其指针域为空,写作为N U L L。 图7 - 3还给出这样一层含义,链表中的各节点在内存的存储地址不是连续的,其各节点的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也可以跳跃式分配地址。 看一下链表节点的数据结构定义: struct node { int num; struct node *p; } ; 在链表节点的定义中,除一个整型的成员外,成员p是指向与节点类型完全相同的指针。 在链表节点的数据结构中,非常特殊的一点就是结构体内的指针域的数据类型使用了未定义成功的数据类型。这是在C中唯一规定可以先使用后定义的数据结构。 ?单链表的创建过程有以下几步: 1 ) 定义链表的数据结构。 2 ) 创建一个空表。 3 ) 利用m a l l o c ( )函数向系统申请分配一个节点。

List-DuLinkedList-将单向循环链表改为双向的

List-DuLinkedList-将单向循环链表改为双向的 2.32 已知有一个单向循环链表,其每个结点中含有三个域:prior,data和next, 其中data为数据域,next为指向后继结点的指针域,prior也为指针域,但它的值为NULL。试编写算法将此单向循环链表改写为双向循环链表,即使prior成为指向前驱结点的指针域#include #include #define N 6 typedef struct DuLNode { //双向循环链表结点 char data; struct DuLNode *prior; struct DuLNode *next; } DuLNode, *DuLinkedList; void createLinkedList(DuLinkedList &L) { //创建双向循环链表(暂时只设NEXT指针)DuLinkedList p; int i; L = (DuLinkedList)malloc(sizeof(DuLNode)); L->data = NULL; L->next = L; L->prior = NULL; for(i=N; i>0; i--) { p = (DuLinkedList)malloc(sizeof(DuLNode)); p->data = getchar(); p->next = L->next; L->next = p; } } void singleToDu(DuLinkedList &L) { //将Prior指针添加上 DuLinkedList p, q; p = L; q = p->next; while(q != L) { q->prior = p; p = q; q = q->next; } q->prior = p; } void printList(DuLinkedList L) { //打印双向循环链表 DuLinkedList p; if(L->prior) { printf("链表的前驱指针存在,现采用反向遍历\n"); p = L->prior; while(p != L) {printf("%c ", p->data); p = p->prior;} } else { printf("链表的前驱指针不存在,将采用正向遍历\n"); p = L->next; while(p != L) {printf("%c ", p->data); p = p->next;} } }

第三章 单链表 题目和答案

第2章自测卷答案 一、填空 1.顺序表中逻辑上相邻的元素的物理位置相互相邻。单链表中逻辑上相邻的元素的物理位置不 相邻。 2.在单链表中,除了首元结点外,任一结点的存储位置由其直接前驱结点值域指示。 3.在n个结点的单链表中要删除已知结点*p,需找到它的地址。 二、判断正误(在正确的说法后面打勾,反之打叉) 1. 链表的每个结点中都恰好包含一个指针。X 2. 链表的物理存储结构具有同链表一样的顺序。X 3. 链表的删除算法很简单,因为当删除链中某个结点后,计算机会自动地将后续的各个单元向前移动。X 4. 线性表的每个结点只能是一个简单类型,而链表的每个结点可以是一个复杂类型。Y 5. 顺序表结构适宜于进行顺序存取,而链表适宜于进行随机存取。Y 6. 顺序存储方式的优点是存储密度大,且插入、删除运算效率高。X 7. 线性表在物理存储空间中也一定是连续的。X 8. 线性表在顺序存储时,逻辑上相邻的元素未必在存储的物理位置次序上相邻。X 9. 顺序存储方式只能用于存储线性结构。X 10. 线性表的逻辑顺序与存储顺序总是一致的。X 三、单项选择题 (A)1. 链接存储的存储结构所占存储空间: (A)分两部分,一部分存放结点值,另一部分存放表示结点间关系的指针 (B)只有一部分,存放结点值 (C)只有一部分,存储表示结点间关系的指针 (D)分两部分,一部分存放结点值,另一部分存放结点所占单元数 (B)2. 链表是一种采用存储结构存储的线性表; (A)顺序(B)链式(C)星式(D)网状 (D)3. 线性表若采用链式存储结构时,要求内存中可用存储单元的地址: (A)必须是连续的(B)部分地址必须是连续的 (C)一定是不连续的(D)连续或不连续都可以 (B)4.线性表L在情况下适用于使用链式结构实现。 (A)需经常修改L中的结点值(B)需不断对L进行删除插入 (C)L中含有大量的结点(D)L中结点结构复杂 (C)5.单链表的存储密度 (A)大于1;(B)等于1;(C)小于1;(D)不能确定 (A)6、在单链表的一个结点中有个指针。

C语言通用数据类型链表的构造数据域为指针

和一般的数据结构里面的链表的实现没什么大不同, 在list.h里面只修改一个地方 typedef void * ElemType; 也就是说数据域是一个无类型指针,链表本身不对这个指针有数据访问,在使用链表的时候我们给一个有类型的指针,在操作的时候编译器有规律可循了,接下来只要链表数据访问的函数了,因为数据域是一个指针,因为没有修改TraverseList函数,那么给函数指针传递的一个指向指针的指针,所以修改遍历数据域访问函数如下 int TraverseList(List*,int (*)(ElemType *));/* 遍历访问,反问某个节点元素用函数处理 */ list.htypedef void * ElemType; typedef struct node { ElemType data; struct node * next; }ChainNode; typedef struct { ChainNode *head; int size; ChainNode *tail; }List; List * CreateList(void); /* 创建链表 */ void DestoryList(List*); /* 销毁链表 */ void ClearList(List*); /* 清空链表 */ int ListAppend(List*,ElemType); /* 追加元素 */ int ListInsert(List*,int,ElemType); /* 加入元素 */ int ListDelete(List *,int); /* 删除第几个元素 */

int GetElem(List*,int,ElemType *); /* 取得第几个元素的值用第三个参数返回 */ ChainNode * GetAddr(List *, int); /* 取得编号为N的元素所在地址 */ int TraverseList(List*,int (*)(ElemType *)); /* 遍历访问,反问某个节点元素用函数处理 */ ChainNode * NewChainNode( ElemType); list.c #include "list.h" /*==================*/ /*==================*/ List *CreateList() { List * pt = 0; ElemType data; pt=(List*)malloc( sizeof(List) ); if( !pt ) return 0; pt->head = NewChainNode(data ); if( ! pt->head ) { free(pt); return 0; } pt->tail = pt->head; return pt; } /*==================*/ void DestoryList(List * plist) { ClearList(plist); free(plist->head); plist->head = 0; free(plist); plist = 0;

(题)数据结构复习题

Ch3链表(共18题,11道算法设计题) 一、选择题 1、设单链表中结点的结构为(data, link)。已知指针q所指结点是指针p所指结点的直接前驱,若在*q与*p之间插入结点*s,则应执行下列哪一个操作? (1)s->link = p->link;p->link = s;(2)q->link = s;s->link = p; (3)p->link = s->link;s->link = p;(4)p->link = s;s->link = q; Key:(2) 2、设单链表中结点的结构为(data, link)。已知指针p所指结点不是尾结点,若在*p之后插入结点*s,则应执行下列哪一个操作? (1)s->link = p;p->link = s;(2)s->link = p->link;p->link = s; (3)s->link = p->link;p = s;(4)p->link = s;s->link = p;Key:(2) 3、设单链表中结点的结构为(data, link)。若想摘除结点*p的直接后继,则应执行下列哪一个操作? (1)p->link = p->link->link;(2)p = p->link;p->link = p->link->link; (3)p->link = p->link;(4)p = p->link->link; Key:(1) 4、设单循环链表中结点的结构为(data, link),且rear是指向非空的带表头结点的单循环链表的尾结点的指针。若想删除链表第一个结点,则应执行下列哪一个操作? (1)s = rear;rear = rear->link;free(s); (2)rear = rear->link;free(rear); (3)rear = rear->link->link;free(rear); (4)s = rear->link->link;rear->link->link = s->link;free(s);

一步一步写算法(之循环单向链表)

软件英才网软件行业驰名招聘网站 一步一步写算法(之循环单向链表) 前面的博客中,我们曾经有一篇专门讲到单向链表的内容。那么今天讨论的链表和上次讨论的链表有什么不同呢?重点就在这个"循环"上面。有了循环,意味着我们可以从任何一个链表节点开始工作,可以把root定在任何链表节点上面,可以从任意一个链表节点访问数据,这就是循环的优势。 那么在实现过程中,循环单向链表有什么不同? 1)打印链表数据 1void print_data(const LINK_NODE* pLinkNode) 2{ 3 LINK_NODE* pIndex = NULL; 4if(NULL == pLinkNode) 5return; 6 7 printf("%d\n", pLinkNode->data); 8 pIndex = pLinkNode->next; 9while(pLinkNode != pIndex){ 10 printf("%d\n", pIndex->data); 11 pIndex = pIndex ->next; 12 } 13} 以往,我们发现打印数据的结束都是判断指针是否为NULL,这里因为是循环链表所以发生了变化。原来的条件(NULL != pLinkNode)也修改成了这里的(pLinkNode != pIndex)。同样需要修改的函数还有find函数、count统计函数。 2)插入数据 14STATUS insert_data(LINK_NODE** ppLinkNode, int data) 15{ 16 LINK_NODE* pNode; 17if(NULL == ppLinkNode) 18return FALSE; 19 20if(NULL == *ppLinkNode){ 21 pNode = create_link_node(data); 22 assert(NULL != pNode);

第三章 链表 基本题

第三章链表 基本题 3.2.1单项选择题 1.不带头结点的单链表head为空的判定条件是 A.head=NULL B.head->next=NULL C.head->next=head D.head!=NULL 2.带头接待点的单链表head为空的判定条件是 A.head=NULL B.head->next=NULL C.head->next=head D.head!=NULL 3.非空的循环单链表head的尾结点(由p所指向)满足 A.p->head=NULL B.p=NULL C.p->next=head D.p=head 4.在循环双链表p的所指结点之后插入s所指结点的操作是 A.p->right=s; s->left=p; p->right->lefe=s; s->right=p->right; B.p->right=s; p->right->left=s; s->lefe=p; s->right=p->right; C.s->lefe=p; s->right=p->right; p->right=s; p->right->left=s; D.s->left=p; s->right=p->right; p->right->left=s; p->right=s; 5.在一个单链表中,已知q所指结点是所指结点p的前驱结点,若在q和p之间插入结点S,则执行 A.s->next=p->next; p->next=s; B.p->next=s->next; s->next=p; C.q->next=s; s->next=p; D.p->next=s; s->next=q; 6.在一个单链表中,若p所指结点不是最后结点,在p之后插入s所指结点,则执行 A.s->next=p; p->next=s; B.s->next=p->next; p->next=s; C.s->next=p->next; p=s; D.p->next=s; s->next=p; 7.在一个单链表中,若删除p所指结点的后续结点,则执行 A.p->next=p->next->next; B.p=p->next; p->next=p->next->next; C.p->next=p->next D.p=p->next->next 8.假设双链表结点的类型如下: typedef struct linknode {int data; /*数据域*/ Struct linknode *llink; /*llink是指向前驱结点的指针域*/ Struct linknode *rlink; /*rlink是指向后续结点的指针域*/ }bnode 下面给出的算法段是要把一个所指新结点作为非空双向链表中的所指结点的前驱结点插入到该双链表中,能正确完成要求的算法段是 A.q->rling=p; q->llink=p->llink; p->llink=q;

指针与链表练习

指针与链表练习 1、围绕着山顶有10 个洞,一只兔子和一只狐狸各住一个洞,狐狸总想吃掉兔子。一天兔子对狐狸说,你想吃我有一个条件,第一次隔一个洞找我,第二次隔两个洞找我,以后依次类推,次数不限。若能找到我,你就可以饱餐一顿,在没找到我之前不能停止。狐狸一想只有10 个洞,寻找的次数又不限,哪有找不到的道理,就答应了条件。结果就是没找着。现请你编写一程序,假定狐狸找了1000 次,兔子躲在哪个洞里才安全。 2、输入一串大写字母,用这些字母建立一个指针链表,然后输出这个链表。链表中可能有一些重复的字母,将重复的多余字母从链表中删除,只留下第1个,输出链表。再将剩余链表中的字符按ASCII码升序重排,然后输出该链表。 例如:输入:DSDFRSSDFGDKAHHAUJDJG 输出:DSDFRSSDFGDKAHHAUJDJG DSFRGKAHUJ ADFGHJKRSU 3、约瑟夫的新问题 源程序文件名 jsf.pas 可执行文件名 jsf.exe 输入文件名 jsf.in 输出文件名 jsf.out 时间限制 1秒 问题描述 将1~M这M个自然数按由小到大的顺序沿顺时针方向围成一圈。以S为起点,先沿顺时针方向数到第N个数就出圈,然后再沿逆时针方向数到第K个数再出圈,再沿顺时针方向数到第N个数就出圈,然后再沿逆时针方向数到第K个数再出圈,……。这样按顺时针方向和逆时针方向不断出圈,直到全部数都出圈为止。 请打印先后出圈的数的序列。 输入格式 文件中共4行,每行为一个自然数,分别表示M,S,N,K。M不超过1000。 输出格式 仅1行,先后出圈的数的序列,每个数之间有1个空格。 样例输入(jsf.in) 8 1 3 2

相关文档
最新文档