实验2 单链表的建立及操作
- 实验要求
1.建立一个带头结点的单链表,结点的值域为整型数据。要求将用户输入的数据按尾插入法来建立相应单链表。
2.设计一个函数在链表中查找元素x的位置,如果x不在链表中则返回-1。
3.设计一个函数将元素x插入第i个元素的后面。如果i大于链表的长度,则将x插入链表的末尾,如果i小于或等于0,则将x直接插入表头之后。
- 实验过程及结果
1.基本思路:
定义一个结点的值域为int型数据,创建一个头结点,先初始化,将它的next指针置为NULL,正位序插入n个元素的值,建立带表头结点的单链表L。
代码显示:
//单链表的建立-尾插法
int CreateList_R(LinkList &L,int n)//正位序插入n个元素的值,建立带表头结点的单链表L
{
L=new Lnode;L->next=NULL;//建立头结点
LinkList p,r;
r=L;
for(int i=0;i<n;++i)
{
p=new Lnode;//生成新结点,
scanf("%d",&(p->data));//输入元素的值
p->next=NULL;
r->next=p;//插入结点到表尾
r=p;//指向新的尾结点
}
return 1;
}
2.基本思路:
先初始化链表使从链表的第一个数据元素开始顺序查找,查找失败的条件为查找的元素值与链表的值不等,这时将返回-1。
代码显示:
//按值查找-根据指定数据的值查找它的位置序号
int LocateElem_L(LinkList L,ElemType e)
{
//找到,则返回L中与e值相等的数据元素的位置序号,查找失败,则返回-1
LinkList p;
p=L->next;int j=1;//初始化
while(p&&p->data!=e)
{
p=p->next;
j++;
}
if(p)return j;
else
return F;
}
3*.基本思路*:
要查找的位置元素i有三种情况:第一种是i的范围是1~n(n为单链表的长度)按要求插入即可;第二种是i<=0,则将它插入到表头之后(此时链表没有遍历查找,p指向的是头结点);第三种情况是i>n+1,p指向NULL,所以在表尾插入较简单。
代码显示:
//插入-在L中第i个位置之后插入数据元素e
Status ListInsert(LinkList &L,int i,ElemType e)
{
LinkList p,s;
p=L;
int j=0;
while(p&&j<(i-1))//寻找第i个结点,p指向第i个结点
{
p=p->next;
++j;
}
if(!p)//当i>表长时,将元素插入表尾
{
s=new Lnode;
s=p->next;
s->data=e;
s=NULL;
}
else if(j>i-1)//当i<1时将元素插入表头之后
{
s=new Lnode;
s->data=e;
s->next=L->next;
L->next=s;
}
else
{
s=new Lnode;
s->data=e;
s->next=p->next;p->next=s;//将结点s插入L中
}
return OK;//插入成功,返回1
}
完整代码如下:
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define F -1
#define ERROR 0
typedef int ElemType;
typedef int Status;
typedef struct Lnode//单链表的定义
{
ElemType data;//数据域
struct Lnode *next; //指针域
}Lnode,*LinkList;
LinkList L;
//建立一个空链表
Status InitList(LinkList &L)
{
L=new Lnode;//L=(LinkList)mallo(sizeof(Lnode));
L->next=NULL;
return OK;
}
//判断链表是否为空
int IsEmpty(LinkList L)
{
if(L->next)//如果L->next==NULL,则链表为空
return 0;
else
return 1;
}
//链表的销毁
Status DestoryList(LinkList &L)
{
LinkList p;
while(L)//当链表不为NULL时,则一直释放结点
{
p=L;
L=L->next;
delete p;
}
return OK;
}
//链表的清空
Status ClearList(LinkList &L)
{
LinkList p,q;
p=L->next;//使p指向首元结点
while(p)//当p指向的结点为NULL时,结束循环
{
q=p->next;
delete p;
p=q;
}
L->next=NULL;
return OK;
}
//求单链表的长度
int ListLength(LinkList L)
{
LinkList p;
p=L->next;//使p指向首元结点
int i=0;
while(p)//当p为NULL时,循环结束
{
i++;//记录结点个数
p=p->next;//结点后移
}
return i;//返回的值是链表中的结点个数(不包括头结点)
}
//取第i个元素的值
Status Getelem(LinkList L,int i,ElemType &e)//获取链表中某个数据元素的内容,通过e返回
{
LinkList p;
p=L->next;int j=1;//初始化
while(p&&j<i)//向后扫描,直到p指向第i个元素的位置或者p为NULL
{
p=p->next;
++j;
}
if(!p||j>i)//第i个元素不存在
return ERROR;
e=p->data;//取第i个元素的值
return OK;
}
//按值查找-根据指定数据的值查找它的位置序号
int LocateElem_L(LinkList L,ElemType e)
{
//找到,则返回L中与e值相等的数据元素的位置序号,查找失败,则返回-1
LinkList p;
p=L->next;int j=1;//初始化
while(p&&p->data!=e)
{
p=p->next;
j++;
}
if(p)return j;
else
return F;
}
//插入-在L中第i个位置之后插入数据元素e
Status ListInsert(LinkList &L,int i,ElemType e)
{
LinkList p,s;//插入-在L中第i个位置之后插入数据元素e
p=L;
int j=0;
while(p&&j<(i-1))//寻找第i个结点,p指向第i个结点
{
p=p->next;
++j;
}
if(!p)//当i>表长时,将元素插入表尾
{
s=new Lnode;
s=p->next;
s->data=e;
s=NULL;
}
else if(j>i-1)//当i<1时将元素插入表头之后
{
s=new Lnode;
s->data=e;
s->next=L->next;
L->next=s;
}
else
{
s=new Lnode;
s->data=e;
s->next=p->next;p->next=s;//将结点s插入L中
}
return OK;//插入成功,返回1
}
//单链表的删除
Status ListDelete(LinkList &L,int i,ElemType &e)
{
//删除链表中第i个位置的数据元素
//先找到第i-1个位置的数据元素
LinkList p,q;
p=L;int j=0;
while((p->next)&&j<i-1)//查找第i-1个位置的数据元素
{
p=p->next;
++j;
}
if(!(p->next)||j>i-1)return ERROR;//删除位置不合理
q=p->next;//临时保存被删结点的地址以备释放
p->next=q->next;//改变被删结点前驱结点的指针域
e=q->data;//保存删除结点的数据域
delete q;//释放删除结点的空间
return OK;
}
//单链表的建立-尾插法
int CreateList_R(LinkList &L,int n)//正位序插入n个元素的值,建立带表头结点的单链表L
{
L=new Lnode;L->next=NULL;//建立头结点
LinkList p,r;
r=L;
for(int i=0;i<n;++i)
{
p=new Lnode;//生成新结点,
scanf("%d",&(p->data));//输入元素的值
p->next=NULL;
r->next=p;//插入结点到表尾
r=p;//指向新的尾结点
}
return 1;
}
//主函数测试
int main()
{
ElemType e;int n;
//测试InitList函数
if(InitList(L))printf("InitList success!\n");
else
printf("InitList error\n");
//测试IsEmpty函数
if(IsEmpty)printf("LinkList is empty\n");
else
printf("LinkList is not empty\n");
//测试CreateList_R函数
printf("请输入建立单链表的数据元素个数:\n");
scanf("%d",&n);
if(CreateList_R(L,n))printf("CreateList success\n");
//测试ListLength函数
printf("LinkList length is %d\n",ListLength(L));
//测试Getelem函数
if(Getelem(L,1,e))printf("The first element is %d\n",e);
else
printf("The first element is not exist\n");
//测试LocateElem_L函数
int a2;
printf("请输入你要查找的元素,若查找成功,会返回该元素的位置序号\n");
scanf("%d",&a2);
int f=LocateElem_L(L,a2);
if(f)printf("%d is located at %d\n",a2,f);
else
printf("%d is not located at the LinkList\n",a2);
//测试ListInsert函数
printf("请输入要插入元素的位置序号及元素的值:\n");
int c,a3;
scanf("%d %d",&c,&a3);
if(ListInsert(L,c,a3))printf("ListInsert success\n");
//测试ListDelete函数
printf("请输入你要删除元素的位置序号:\n");
int d;
scanf("%d",&d);
if(ListDelete(L,d,e))printf("删除的元素是:%d\n",e);
else
printf("Delete error\n");
//测试ClearList函数
if(ClearList(L))
printf("ClearList success\n");
else
printf("ClearList error\n");
//测试DestoryList函数
if(DestoryList(L))printf("DestoryList success\n");
else
printf("DestoryList error\n");
return 0;
测试结果:
- 实验总结
链式存储结构
结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。
线性表的链式表示又称为非顺序映像或链式映像。
单链表的查找、插入、删除算法时间效率分析
因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间为O(n);
因线性链表不需要移动元素,只要修改指针,一般情况下时间复杂度为O(1),
但是,如果要在单链表中进行前插或删除操作,由于要从头查找前驱结点,所耗时间复杂度为O(n)。
嘿嘿嘿
洛阳亲友如相问,就说我在敲代码