数据结构实验报告
- 问题描述及分析
问题描述:
2-23设计循环单链表。要求:
(1)循环单链表的操作,包括初始化,求数据元素个数,插入、删除、取数据元素。
(2)设计一个测试主函数实际运行验证所设计循环单链表的正确性。
分析:首先建立一个循环单链表软工具箱,然后根据题目要求,能够在循环单链表的任意位置插入、删除结点以及确定某一元素在链表中的位置。
- 建立循环单链表功能
建立一个带头结点的循环单链表,确定DataType与Node。
- 初始化
将带头结点的循环单链表初始化。
- 插入功能
输入的形式:在带头节点的单链表head的第i个(0~size)个结点前插入一个存放元素x的结点,首先要在单链表中找到ai-1结点并由指针p指示,然后动态申请一个内存单元并由指针q指示,并把元素x的值赋予新的结点的数据域(即q->data=x),最后修改新的结点的指针指向ai的结点(q->next=p->next),并修改ai-1结点的指针域使之指向新结点q(即p->next=q).
循环条件:子条件p->next!=head保证指针所指结点存在,子条件j<i-1保证最终让指针p指向ai-1结点
输出的形式:如果输入的参数不合法,则显示参数错误信息。
返回值:插入成功返回1,插入失败返回0。
- 删除功能
输入的形式:要在带头结点的单链表中删除ai结点,首先要在单链表中寻找到ai-1结点并由指针p指示,然后让指针s指向ai结点(s=p->next),并把ai结点数据域赋予元素x(*x=s->data),最后把ai结点脱链(p->next=p->next->next),并动态释放ai结点的内存单元(free(s)).
循环条件:p->next!=head保证ai-1存在;p->next->next!=head保证ai结点存在;j<i-1保证最终让指针p指向ai-1结点。
输出的形式:如果输入的参数不合法或顺序表为空,则显示参数错误信息。
返回值:删除成功返回1,删除失败返回0。
- 查找功能
输入的形式:取元素函数和删除函数基本类同,但取元素函数的循环条件改为j<i,并且不删除ai结点
输出的形式:如果输入的参数不合法,则显示参数错误信息。
返回值:查找成功返回1,查找失败返回0。
2.概要设计
(1)为了实现上述程序功能,先定义一个简化的包含抽象数据类型的头文件
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node *next;
}SLNode;
void ListInitiate(SLNode **head);//初始化
int ListLength(SLNode *head);//求当前元素个数
int ListInsert(SLNode *head,int i,DataType x);//插入
int ListDete(SLNode *head,int i,DataType *x);//删除
int ListGet(SLNode *head, int i,DataType *x);//取元素
void Destroy(SLNode **head);//撤销
(2)程序包含的模块
主函数main()
初始化函数 ListInitiate(SLNode **head);
插入元素函数ListInsert(SLNode *head,int i,DataType x);
删除元素函数ListDelete(SLNode *head,int i,DataType *x);
提取元素函数ListGet(SLNode *head, int i,DataType *x);
当前元素个数函数ListLength(SLNode *head);
(3)主函数的伪码
main(){
定义一个单链表SLNode;
初始化SLNode;
建立SLNode;
删除某一元素;
循环以下处理,直至结束:
{
取顺序表元素并输出;
}
}
3.详细设计
结合概要设计中定义的包含抽象类型的头文件,进行数据结构设计和算法设计。
- 数据结构
链表中的结点的结构体定义如下:
typedef int DataType;
typedef struct Node
{
DataType data;
struct Node *next;
}SLNode;
- 基本操作的伪码算法
初始化循环单链表
void ListInitiate(SLNode **head){ //初始化
*head=(SLNode *)malloc(sizeof(SLNode));//申请头结点,由head指示其地址
(*head) ->next=*head;//置结束标记*head
}
返回当前元素个数
int ListLength(SLNode *head){ //求当前元素个数
SLNode *p =head; //p指向头结点
int size =0; //size初始为0
while(p->next !=head)//循环计数
{
p=p->next;
size++;
}
return size;
}
插入元素
int ListInsert(SLNode *head,int i,DataType x){
//在带头结点的单链表head的第i(0<=i<=size)个结点前插入存放一个数据元素x的结点
//插入成功则返回1,失败则返回0
SLNode *p,*q;
int j;
p=head;
j=-1;
while(p->next!=head&&j<i-1)
//最终让指针p指向第i-1个结点
{
p=p->next;
j++;
}
if(j!=i-1)
{
printf("插入元素位置参数错!");
return 0;
}
q=(SLNode *)malloc(sizeof(SLNode));//生成新结点
q->data =x; //新结点数据域赋值
q->next =p->next; //插入步骤1
p->next =q; //插入步骤2
return 1;
}
删除元素
Int ListDelete(SLNode *head, int i,DataType *x){
//删除带头结点单链表head的第i(0<=i<=size-1)个结点
//被删除结点的数据域值由x带回,删除成功则返回1,失败则返回0
SLNode *p,*s;
int j;
p=head;
j=-1;
while(p->next !=head && p->next->next!=head &&j<i-1){
//循环结束时指针p指向第i-1个结点
p=p->next;
j++;
}
if(j!=i-1)
{
printf(“删除元素位置参数错!”);
return 0;
}
s=p->next;//指针s指向ai结点
*x=s->data;//把指针s所指的结点的数据域赋值给x
p->next = p->next->next;//删除
free(s);//释放指针s所指结点的内存空间
return 1;
}
取元素
Int ListGet(SLNode *head, int i,DataType *x){
SLNode *p;
int j;
p=head;
j=-1;
while(p->next!=head&&j<i)
{
p=p->next;
j++;
}
if(j!=i)
{
printf(“取元素位置参数错!”);
return 0;
}
*x =p->data;
return 1;
}
撤销
void Destroy(SLNode **head){
SLNode *p,*p1;
p=*head;
While(p!=NULL)
{
p1=p;
p=p->next;
free(p1);
}
*head=NULL;
}
主程序:
#include<stdio.h>//包含printf()函数
#include<malloc.h>//包含malloc()函数
#include"LinList.h"//包含LinList.h头文件
typedef int DataType;//包含DataType为int
typedef struct Node
{
DataType data;
struct Node *next;
}SLNode;
int ListDelete(Node *head,int i, DataType x);
int ListGet (Node *head, int i, DataType *x);
int ListInsert(Node *head, int i, DataType x);
void print(Node *head);
Node *ListInitiate();
void main (void)
{
int i=4;
Node *p;
p=ListInitiate();
print(p);
ListLength(p);
printf("链表长度:\n");
printf("%d \n",ListLength(p));
{
ListInsert(p,i,i+1);
printf("插入一个元素后:\n");
print(p);
ListDelete(p,i, i+1);
printf("删y插入元素后:\n");
print(p);
}
{
ListDelete(p,i, i+1);
printf("删除一个元素后:\n");
print(p);
}
}
Node *ListInitiate() //创建单链表返回一个指向链表表头结点的指针head
{
Node *head,*q,*p; //定义指针变量
int a,n;
printf("输入链表长度n:\n"); //链表大小为n
scanf("%d",&n);
head=(Node *)malloc(sizeof(Node));//申请新的存储空间,建立表头结点
head->data=n;
q=head;
while(n>0)
{
scanf("%d",&a); //输入链表元素
p=(Node*)malloc(sizeof(Node));
p->data=a;
q->next=p;
q=p;
n=n-1;
}
q->next=NULL;
return(head); //返回表头指针head}
void print(Node *head) //输出单链表各个元素
{
Node *p;
p=head->next;
while(p!=NULL)
{
printf("% d",p->data);
p=p->next;
}
printf("\n");
}
int ListLength(Node *head)//测元素个数
{
Node *p=head;
int size=0;
while(p->next!=NULL)
{
p=p->next;
size++;
}
return size;
}
int ListInsert(Node *head, int i, DataType x)//插入元素
{
Node *p,*q;
int j;
p=head;
j=-1;
while(p->next!=NULL && j<i-1)//最终让指针p指向第i-1个位置
{
p=p->next;
j++;
}
if(j!=i-1)
{
printf("插入元素位置参数错误!\n");
return 0;
}
q=(Node *)malloc(sizeof(Node));//生成新结点
q->data=x;//新结点数据域赋值
q->next=p->next;
p->next=q;
return 1;
}
int ListDelete(Node *head,int i, DataType x)
{
Node *p,*s;
int j;
p=head;
j=-1;
while(p->next!=NULL && p->next->next!=NULL && j<i-1)//循环结束时指针p指向第i-1个位置
{
p=p->next;
j++;
}
if(j!=i-1)
{
printf("删除元素位置参数错误!\n");
return 0;
}
s=p->next;//指针s指向ai结点
x=s->data;//把s所指结点数据域值赋给x
p->next=p->next->next;//删除
free(s);//释放指针s所指结点的内存空间
return 1;
}
int ListGet (Node *head, int i, DataType *x)//取元素
{
Node *p;
int j;
p=head;
j=-1;
while(p->next!=NULL&&j<i)
{
p=p->next;
j++;
}
if(j!=i){
printf("取元素位置参数错误!\n");
return 0;
}
*x=p->data;
return 1;
}
}
5.调试与分析
该结果与预期结果一致,说明所设计的单循环链表是正确的。
- 总结
书中已经给出初始化、查找、插入、删除等函数代码,但做完后大大加深了自己对书中各个知识点的印象和理解,也学会了一写编写算法的小技巧,要有耐心,多看书多实践,做数据结构上机实验感觉困难重重,有很多不懂的地方,由于以前C语言学得不是很扎实,所以在编写程序时候遇到很多问题,很多地方是照着课本上的源程序复制下来的,不知其原理。多亏有班上这方面学得好的同学的悉心指导才得以把程序做出来,当然,通过这个实验也学到很多东西,