//以前的实验报告被我找到了,找知道还在就不用QQ空间上的截图了,代码很糟糕,那是因为本人还是菜鸟
一,顺序存储
内容:此线性表采用顺序存储,实现了初始化、建表、查找、删除、打印,清空,销毁,返回前去后继等功能。
---------------函数功能实现------------------
void InitList(sqList *L)
{
(*L).elem = (int*)malloc(LIST_INIT_SIZE*sizeof(int));
//申请空间,将首地址赋给表指针作为基址
if(!(*L).elem) exit(0);//如果申请失败就退出
(*L).length =0;//表长为空,无数据
(*L).listsize =LIST_INIT_SIZE;//容量赋值
}//创建空表
void creatlist(sqList *L)
{
int n,x,i;
printf("请输入要存储的数据个数\n");
scanf("%d",&n);
printf("请输入数据:\n");
for(i=1;i<=n;i++)//循环读入数据
{
scanf("%d",&x);
(*L).elem[i] = x;
}
(*L).length = n;//别忘了为表长赋值
}//输入数据
int destroyList(sqList *L){
int i;
if ((*L).elem)//线性表存在,则继续执行
{
free((*L).elem);
(*L).elem = NULL;
printf("\n\n--线性表销毁完毕--\n");
}
else {printf("\n\n--表不存在--\n");return FALSE;}//否则错误退出
return OK;
}//销毁线性表
void clearlist(sqList *L){
(*L).length=0; //将线性表的长度置为0
printf("\n\n--线性表清空完毕--\n");//清空即是让数据清空,表长为0即是无数据(可看上面)
}//清空线性表
int ListEmpty(sqList *L){
if ((*L).length==0)//同样道理,通过判定表长便可以确定线性表是否为空
{
printf("\n\n线性表为空!!\n");
return TRUE;
}
else
{
printf("\n\n线性表不为空!!\n");
return FALSE;
}
}//判断线性表是否为空
int ListLength(sqList *L){
printf("\n\n--线性表长度为:%d--\n",(*L).length);//没啥说的,直接返回线性表成员length的大小即可
return ((*L).length);
}//返回线性表长度
int GetElem(sqList *L,int i,int e)
{
if (i<1||i>(*L).length) {return 0;}
//判断i值是否合理,若不合理,返回ERROR
else e = (*L).elem[i];//位序正确,即把对应的线性表成员中的元素elem[i]作为返回值
return e;
}//返回特定位序的元素
int LocateELem(sqList *L,int i,int e)
{
for (i=1;i <= (*L).length;i++)//结合上面的输入数据(creatlist)的函数,从1开始遍历
if ((*L).elem[i]==e) return i;//找到则返回1
if(i = (*L).length&&(*L).elem[i] != e)
return ERROR;//找不到则返回0
}//定位特定元素的位序
int priorelem(sqList *L,int cur_e,int pre_e){
int i;
if((*L).elem == NULL)//判断线性表是否存在,不存在则退出
{
printf("--表不存在--\n");
exit(0);
}
for(i=1;((*L).elem[i]!=cur_e)&&(i<=(*L).length);i++);//利用for循环遍历
//循环出来之后即是elem[i]=cur_e
if(i<=(*L).length)
printf("\n--当前位序:%d--\n",i);//方便查看当前位置
else
{printf("\n--位序过界--\n");return(FALSE);}
if((*L).elem[i] == cur_e)
pre_e = (*L).elem[i-1];//记录位序的前一个元素数据
else
{printf("\n--%d不存在于表中--\n",cur_e);return (FALSE);}
return pre_e;
}//返回特定元素的前驱
int nextelem(sqList *L,int cur_e,int next_e){
int i=1;
if((*L).elem == NULL)
{
printf("--is null--\n");
exit(0);
}
for(i=1;(*L).elem[i]!=cur_e&&i<=(*L).length;i++);
if(i<=(*L).length)
printf("\n--当前位序:%d--\n",i);
if(i<(*L).length)
next_e = (*L).elem[i+1];
else
{printf("\n--%d的后继不存在--\n",cur_e);return (FALSE);}
return next_e;
}//返回特定元素的后继
int ListInsert_sq(sqList *L,int i,int e)
{
if(i < 1||i > (*L).length+1) {
printf("\n--位序不存在,插入错误--\n");return ERROR;}
if((*L).length >= (*L).listsize){
newbase=(int*)realloc((*L).elem,
((*L).listsize+LISTINCREMENT)*sizeof(int));
//空间不足,则增加空间然后将数据复制入新的存储空间
if(!newbase) exit(0);//空间申请失败,则退出
(*L).elem = newbase;//新基址(首地址)
(*L).listsize += LISTINCREMENT; //增加存储容量
}
q = &((*L).elem[i]);//q为插入位置
++(*L).length;//关键:先将空间增一,那么length-1即是原表的最后一个位置
for(p = &((*L).elem[(*L).length-1]);p>=q;--p) *(p+1) = *p;//从(原)表尾开始右移
*q = e;
return OK;}
int ListDelete_sq(sqList *L,int i,int e){
if(i <1||i>(*L).length ) {
printf("\n--位序不存在,无法删除--\n");return -1;}
p = &((*L).elem[i]);//被删除元素位置
e = *p;//将被删除的元素的值赋给e
q = (*L).elem + (*L).length;//表尾元素的位置
for(++p;p <= q;++p) *(p-1) = *p;//被删除元素的下一个开始左移
--(*L).length;
return e;
}//删除位序i的元素,并用e返回其值
int ListTraverse(sqList *L){
int i;
printf("\n列表如下:\n\n");
printf("位序 | ");
for(i=1;i<=(*L).length;i++)
{ if((*L).elem[i]<100)
printf("%2d ",i);
else if( (*L).elem[i] <1000)
printf("%3d ",i);
}
printf("\n——————————————————————\n");
printf("数据 | ");
for(i=1;i<=(*L).length;i++)//格式对齐采用不同精度
{ if((*L).elem[i]<100)
printf("%2d ",(*L).elem[i]);
else if( (*L).elem[i] <1000)
printf("%3d ",(*L).elem[i]);
}
printf("\n");
return OK;
}
——————————顺序表主函数(测试)————————————
void main()
{
int cur_e;
int pre_e;
int next_e;
int e;
int i;
sqList myl;
/*测试函数*/
sqList *L = &myl;//申请指针空间
InitList(L);//创建线性表
creatlist(L);//测试输入
ListTraverse(L);//输出查看
/*前驱函数*/
printf("\n\n请输入表内数据,系统将会找出其的前驱:\n");
scanf("%d",&cur_e);
pre_e = priorelem(L,cur_e,pre_e);
if(pre_e != FALSE)
printf("--%d的前驱是:%d--",cur_e,pre_e);
/*后继函数*/
printf("\n\n请输入表内数据,系统将会找出其的后继:\n");
scanf("%d",&cur_e);
next_e = nextelem(L,cur_e,next_e);
if(next_e != FALSE)
printf("--%d的后继是:%d--",cur_e,next_e);
/*表长函数*/
ListLength(L);
/*查找元素输出位序函数*/
printf("\n\n请输入你要查找的元素位序:\n");
scanf("%d",&i);
e = GetElem(L,i,e);
if(e == 0)
printf("\n\n--线性表中不包含该位序,查找失败--\n");
else
printf("\n--线性表位序%d处的元素为:%d--\n",i,e);
/*定位元素位序函数*/
printf("\n\n请输入你要查找的元素,系统将返回它的位序:\n");
scanf("%d",&e);
i = LocateELem(L,i,e);
if(i == 0)
printf("\n\n--线性表中找不到该元素,查找失败--\n");
else
printf("\n\n该元素的位序为:%d\n",i);
/*插入函数*/
printf("\n\n请输如你要插入的数据和该数据插入的位置:\n");
scanf("%d%d",&e,&i);
ListInsert_sq(L,i,e);
ListTraverse(L);
/*删除函数*/
printf("\n\n请输入你要删除的位序:\n");
scanf("%d",&i);
e = ListDelete_sq(L,i,e);
if(e != -1)
printf("\n\n--位序%d的元素:%d已被删除--\n",i,e);
ListTraverse(L);
}
二.链式存储
内容:此线性表采用链式存储,实现了初始化、建表、查找、删除、打印,清空,销毁,返回前去后继等功能。
DAT *InitList(DAT *head)//创建空表
{
head = (DAT *)malloc(LEN);
if(!head)
{printf("\n--链表创建失败--\n");exit(FALSE);}
head ->next = NULL;
return head;
}
DAT *creatList(DAT *head)//数据录入
{
DAT *p1,*p2;
char ch;
int n = 1;
head = (DAT *)malloc(LEN);
p1 = p2 = (DAT *)malloc(LEN);
if(p1 != NULL)
{
printf("\n请输入数据:\n");
scanf("%d",&p1->data);//p1每一次存储都需要申请空间
head -> next = p1;//注意:本程序的头结点不存储数据 //p2 = p1;为什么这步可以省略呢?就是因为p1,p2在申请空间的时候被赋予的地址是一致的!
printf("\n继续录入(y/any other keys to exit)?\n");
getchar();
scanf("%c",&ch);
while(ch == 'Y'||ch == 'y')
{
printf("\n请输入数据:\n");
p1 = (DAT *)malloc(LEN);
if(p1 != NULL)
scanf("%d",&p1->data);
p2 -> next = p1;
p2 = p1;
printf("\n继续录入(y/any other keys to exit)?\n");
getchar();
scanf("%c",&ch);
}
p2 -> next = NULL;//p2作为连接新建节点的指针,如果next为空,那自然是结束了录入
printf("\n--录入结束--\n");
}
return head;
}
int ClearList(DAT *head) //保留头结点,其余节点数据清空
{
if(head == NULL)
{
printf("\n--表不存在--\n");
return FALSE;
}
DAT *p,*q;
p = head -> next;
while(p)
{
q=p->next;//用声明的另一个指针q来记录p的下一节点的位置
printf("\n--已删除表中数据:%d--\n",p -> data);
free(p);
p=q;//结合q = p -> next,此语句的作用即是让p往后移动,从而实现逐个清空数据的目的
}//直至p为空的时候便是结束了循环,清空结束
head -> next = NULL; //数据清空之后头结点的指针域为空
return TRUE;
}
DAT *destroyList(DAT *head)//销毁 {
if(head == NULL)
{
printf("\n--表不存在,销毁无效--\n");
exit(FALSE);
}
DAT *p;
p = head;
while(head)
{
p = head -> next;
free(head);//第一次循环的时候清除了头结点
head = p;
}
printf("\n--链表销毁结束--\n");
return head;
}
int ListLength(DAT *head)
{
DAT *p;
int i = 0;
p = head -> next;
while(p)
{
i++;
p = p -> next;
}
printf("\n--链表长度为:%d--\n",i);
return i;
}
void ListTraverse(DAT *head)//输出函数
{
DAT *p = head -> next;
DAT *q = p;//位序输出遍历需要
int n = 0;
int length;
length = ListLength(head);
if(p)
{
printf("\n位序 | ");
for(n = 1;n <= length;n++)
{
if(q -> data <10)
printf("%d ",n);
else if(q -> data <100)
printf("%2d ",n);
else
printf("%3d ",n);
q = q -> next;
}
printf("\n------------------------------------\n");
printf("数据 | ");
do
{
printf("%d ",p -> data);
p = p -> next;
}
while(p);
}
printf("\n");
}
int GetElem(DAT *head,int i,int e)
{
int n = 1;
DAT *p;
p = head ->next;
while(p && n < i )//当p不为空且初始位序小于查找位序的时候
{
p = p -> next;//指针后移直至与查找位序相等为止推出循环
n++;
}
if(!p || n > i)
{printf("\n--找不到该位序--\n");return FALSE;}
e = p -> data;
return e;
}
int LocateElem(DAT *head,int e)//查找e的位序,并将其位序返回
{
DAT *p;
int i = 1;
printf("\n请输入你要查找的数据:\n");
scanf("%d",&e);
p = head -> next;
while(p)
{
if(p -> data == e)
{
printf("\n--%d的位序为:%d--\n",e,i);
return i;
}
else
p = p -> next;
i++;
}
printf("\n--找不到该元素--\n"); return 0;
}
int PirrorElem(DAT *head,int cur_e,int pre_e)//查找元素的前驱
{
printf("\n请输入表中数据,系统将会返回其的前驱:\n");
scanf("%d",&cur_e);
if(head == NULL)
{
printf("\n--表不存在--\n");
return FALSE;
}
DAT *p,*q;
q = head -> next;//q指向第一个节点
while(p)
{
p = q -> next;//p指向q的下一节点
if( q -> data == cur_e)//cur_e为第一个元素的时候,提示错误
{
printf("\n--表中第一个元素是没有前驱的,无法查找--\n");
return FALSE;
}
if(p -> data == cur_e)//如果p指针找到了cur_e,就用q返回前驱
{
pre_e = q -> data;
printf("\n--%d的前驱是:%d--\n",cur_e,pre_e);
return pre_e;
}
else
{
if( p -> next != NULL)
q = p;//p,q指针相连,q后移也会带动p的后移
else// p遍历结束达到NULL的时候即是没有找到输入的数据,提示错误
{
printf("\n--表中无此数据--\n");
return FALSE;
}
}
}
}
int NextElem(DAT *head,int cur_e,int next_e)//查找元素的后继
{
DAT *p,*q;
printf("\n请输入数据,系统将会返回其的后继:\n");
scanf("%d",&cur_e);
p = head -> next;
while(p)
{
q = p -> next;
if( p -> data == cur_e && p -> next != NULL)//p没有下一节点的话,也就没有后继之说了
{
next_e = q -> data;
printf("\n-%d的后继为:%d--\n",cur_e,next_e);
return next_e;
}
if( p -> data != cur_e)
{
p = q;//p -> next 不为空的时候,p,q后移遍历
if( p -> next == NULL && p -> data == cur_e )//判断是否有后继
{
printf("\n--末位数据无法查找后继--\n");
return FALSE;
}
if( p -> next == NULL && p ->data != cur_e)//判断时候存在cur_e
{
printf("\n--表中不存在该元素--\n");
return FALSE;
}
}
}
}
DAT *ListInsert(DAT *head,int i,int e)//按位序i插入特定元素e
//定义结构体指针函数,用于返回结构体指针head
{
printf("\n请输入插入的位序和元素\n");
scanf("%d%d",&i,&e);
DAT *p = head;//和下面n = 0相对应,head无数据
DAT *q;
int n = 0;
while(p != NULL && n < i-1)//找到i的前一个节点
{
p = p -> next;//循环第一次的时候p便指向了第一个节点,和n=1对应
n++;//n = 1
}//出循环时n=i-1,p也就指向了i的前一位序
if(p == NULL || n > i-1)//i过大(插入的位序的前一个如果还是空的话,那就超出了插入范围)或过小的时候报错,退出
{
printf("\n--位序错误,插入失败--\n");
return head;
}
q = (DAT *)malloc(LEN);//新节点空间申请
q -> data = e;//新节点赋值
q -> next = p->next;//新节点定位(p -> next为第i个节点),将新节点与原表中第i个节点相连,即是替换了第i的位置
//如果是表尾插入的话,q -> next == NULL
p -> next = q;//再将新节点与前面的p节点相连,即完成了插入
printf("\n--%d已添加到表中第%d位序--\n",e,i);
return head;//返回头指针,方便打印链表
}
DAT *ListInsert_last(DAT *head,int e)//表尾插入函数
//定义结构体指针函数,用于返回结构体指针head
{
int leng = ListLength(head);
DAT *p = head;//和下面n = 0相对应,head无数据
DAT *q;
int n = 0;
while(p != NULL && n < leng)//找到尾节点,在尾节点的后一节点添加数据
{
p = p -> next;//循环第一次的时候p便指向了第一个节点,和n=1对应
n++;//n = 1
}//出循环时n=leng,p也就指向了表尾
if(p == NULL || n > leng)//i过大(插入的位序的前一个如果还是空的话,那就超出了插入范围)或过小的时候报错,退出
{
printf("\n--位序错误,插入失败--\n");
return head;
}
q = (DAT *)malloc(LEN);//新节点空间申请
q -> data = e;//新节点赋值
q -> next = p->next;//新节点定位(p -> next为第i个节点),将新节点与原表中第i个节点相连,即是替换了第i的位置
//如果是表尾插入的话,q -> next == NULL
p -> next = q;//再将新节点与前面的p节点相连,即完成了插入
printf("\n--%d已添加到表尾--\n",e);
return head;//返回头指针,方便打印链表
}
DAT *ListDelete(DAT *head,int i,int e)
{
printf("\n请输入你要删除的位序:\n");
scanf("%d",&i);
DAT *p = head;
DAT *q;
int n = 0;
while(p -> next != NULL && n < i - 1)//循环是为了找到要删除的节点的前驱,即p指向删除节点的上一个节点
{
p = p -> next;
n++;
}
if(p -> next == NULL || n > i -1)//i过大或过小的时候报错退出(要删除的节点不能为空)
{
printf("\n--位序错误,删除失败--\n");
return head;
}
q = p -> next;//q指向p的下一节点
p -> next = q -> next;//将p的下一节点绕到q的下一节点上去,完成对q节点的孤立,将q节点删除
e = q -> data;//用e返回被删除的节点上的数据
free(q);
printf("\n--表中第%d位序上的数据:%d已被删除--\n",i,e);
return head;
}
—————————单向链表主函数——————————
void main()
{
DAT *L1,*L2;
int i,e;
int cur_e;
int pre_e;
int next_e;
//开始测试函数
L1 = InitList(L1);//创建空表
L2 = InitList(L2);
//L1 = ListInsert(L1,i,e);
L1 = creatList(L1);//输入数据
ListTraverse(L1);
L2 = creatList(L2);
ListTraverse(L2);
//ListTraverse(L1);//输出数据
ListLength(L1);//输出链表长度
//ClearList(L1);//清空数据
//ListTraverse(L1);//输出清空效果
//destroyList(L1);
//ListTraverse(L1);
//查找位序上的元素数据
/*printf("\n请输入你要查找的位序:\n");
scanf("%d",&i);
e = GetElem(L1,i,e);
if(e != FALSE)
printf("\n--位序%d上的数据为:%d--\n",i,e);*/
//返回前驱
//PirrorElem(L1,cur_e,pre_e);
//返回后继
//NextElem(L1,cur_e,next_e);
//按位序插入新数据
//L1 = ListInsert(L1,i,e);
//按位序删除数据
//L1 = ListDelete(L1,i,e);
//表尾插入函数(拓展,方便进行合并链表的操作)
/*printf("\n请输入要你在表尾插入的数据:\n");
scanf("%d",&e);
L1 = ListInsert_last(L1,e);
ListTraverse(L1);*/
//用自建函数合并两个不同数据的链表
MergerLinks(L1,L2);//后面再做说明
}
三.单向链表基本函数的运用,合并链表(未排序)
void MergerLinks(DAT *L1,DAT *L2)
{
DAT *L3 = NULL;
DAT *p1 = NULL;
DAT *p2 = NULL;
DAT *p3 = NULL;
DAT *p4 = NULL;
DAT *p5 = NULL;
int n = 0;
int m = 0;
int leng1;
int leng2;
int leng3;
int i = 0,j = 0,k = 0;
p1 = L1;
p2 = L2;
leng1 = ListLength(L1);
leng2 = ListLength(L2);//链表长度获取
L3 = (DAT *)malloc(sizeof(DAT));//第三链表的建立,用于存储表一和表二中不重复的数据
p3 = p4 = (DAT *)malloc(sizeof(DAT));
if(leng1 >= leng2)
{
for(i = 0;i < leng2;i++)
{
if(p2 -> next != NULL)
{p2 = p2 -> next;}
for(j = 0; j < leng1;j++)
{
if(p1 -> next != NULL)
{
p1 = p1 -> next;
}
else//p1 -> next ==NULL的时候
{
p1 = L1 -> next;//重置p1回到L1的第一个节点
}
if(p2 -> data != p1 -> data)//表三数据链表的录入
{
printf("\n--%d--\n",p2->data);
printf("\n-|%d|-\n",p1->data);
m++;
printf("\nm = %d\n",m);
if(m == leng1)//将表二的一个数对比表一中所有的数,如果都不一样则将这个数插入表三
{
p3 -> data = p2 -> data;
if(p3 -> data != NULL)
{
n++;
if(n == 1)
L3 -> next = p3;
else
p4 -> next = p3;
p4 = p3;
p3 =(DAT*)malloc
(sizeof(DAT));
}
p4 -> next = NULL;
m = 0;//重置m
}
}
}
if(m next = NULL;
if(L3 -> next != NULL)
{
printf("\n待插入的数据如下:\n");
ListTraverse(L3);
p5 = L3 -> next;
for(k = 0;k < n;k++)//n即为表三的长度
{
if(p5 -> data != NULL)
{
leng1 = leng1 +1;
L1 = ListInsert_last(L1,p5 -> data);//调用表尾插入函数
}
p5 = p5 -> next;
}
}
printf("\n--合并之后的链表如下:--\n");
ListTraverse(L1);
}
else//leng1 < leng1的情况
{
for(i = 0;i < leng1;i++)
{
if(p1 -> next != NULL)
{p1 = p1 -> next;}
for(j = 0; j < leng2;j++)
{
if(p2 -> next != NULL)
{ p2 = p2 -> next;}
else
{p2 = L2 -> next;}
if(p1 -> data != p2 -> data)//表三数据链表的录入
{
m++;
if(m == leng2)//将表二的一个数对比表一中所有的数,如果都不一样则将这个数插入表三
{
p3 -> data = p1 -> data;
if(p3 -> data != NULL)
{
n++;
if(n == 1)
L3 -> next = p3;
else
p4 -> next = p3;
p4 = p3;
p3 = (DAT*)malloc
(sizeof(DAT));
}
p4 -> next = NULL;
m = 0;//重置m
}
}
}
if(m next = NULL;
if(L3 -> next != NULL)
{
ListTraverse(L3);
p5 = L3 -> next;
for(k = 0;k < n;k++)//n即为表三的长度
{
if(p5 -> data != NULL)
{
leng2 = leng2 +1;
L2 = ListInsert_last(L2,p5 -> data);
}
p5 = p5 -> next;
}
}
printf("\n--合并之后的链表如下:--\n");
ListTraverse(L2);
}
}