线性表的存储以及相关操作实现

来源:互联网 发布:cg软件有哪些 编辑:程序博客网 时间:2024/05/17 07:40

//以前的实验报告被我找到了,找知道还在就不用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;}elsep = 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 == NULLp -> 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 == NULLp -> 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 <leng1)//m小于leng1说明有数重复,为了下一个数的比较可以顺利进行,标志m也要重置 m=0;}        if(n==0)//结束查找,L3表中没有一个数据(n=0)L3 -> 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<leng2)        m=0;}               if(n==0)L3 -> 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);   }} 



原创粉丝点击