数据结构 线性表的单链表存储结构表示和实现
参考代码如下:
- /*
- 名称:线性表的单链表存储结构表示和实现
- 编译环境:VC++6.0
- 日期: 2014-3-27
- */
- #include <stdio.h>
- #include <malloc.h>
- #include <stdlib.h>
- typedef int ElemType;
- // 线性表的单链表存储结构
- typedef struct LNode
- {
- ElemType data; //数据域
- struct LNode *next; //指针域
- }LNode,*LinkList;
- // typedef struct LNode *LinkList; // 另一种定义LinkList的方法
- // 构造一个空的线性表L
- int InitList(LinkList *L)
- {
- /*
- 产生头结点L,并使L指向此头结点,头节点的数据域为空,不放数据的。
- void * malloc(size_t)
- 这里对返回值进行强制类型转换了,返回值是指向空类型的指针类型。
- */
- (*L) = (LinkList)malloc( sizeof(struct LNode) );
- if( !(*L) )
- exit(0); // 存储分配失败
- (*L)->next = NULL; // 指针域为空
- return 1;
- }
- // 销毁线性表L,将包括头结点在内的所有元素释放其存储空间。
- int DestroyList(LinkList *L)
- {
- LinkList q;
- // 由于单链表的每一个元素是单独分配的,所以要一个一个的进行释放
- while( *L )
- {
- q = (*L)->next;
- free( *L ); //释放
- *L = q;
- }
- return 1;
- }
- /*
- 将L重置为空表,即将链表中除头结点外的所有元素释放其存
- 储空间,但是将头结点指针域置空,这和销毁有区别哦。不改变L,所以
- 不需要用指针。
- */
- int ClearList( LinkList L )
- {
- LinkList p,q;
- p = L->next; // p指向第一个结点
- while( p ) // 没到表尾则继续循环
- {
- q = p->next;
- free( p ); //释放空间
- p = q;
- }
- L->next = NULL; // 头结点指针域为空,链表成了一个空表
- return 1;
- }
- // 若L为空表(根据头结点L->next来判断,为空则是空表),则返回1,
- // 否则返回0。
- int ListEmpty(LinkList L)
- {
- if( L->next ) // 非空
- return 0;
- else
- return 1;
- }
- // 返回L中数据元素个数。
- int ListLength(LinkList L)
- {
- int i = 0;
- LinkList p = L->next; // p指向第一个结点
- while(p) // 没到表尾,则继续循环
- {
- i++;
- p=p->next;
- }
- return i;
- }
- // L为带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并
- // 返回1,否则返回0。
- int GetElem(LinkList L,int i,ElemType *e)
- {
- int j = 1; // j为计数器
- LinkList p=L->next; // p指向第一个结点
- while(p&&j<i) // 顺指针向后查找,直到p指向第i个元素或p为空
- {
- p=p->next;
- j++;
- }
- if(!p||j>i) // 第i个元素不存在
- return 0;
- *e = p->data; // 取第i个元素
- return 1;
- }
- // 返回L中第1个与e满足关系compare()的数据元素的位序。
- // 若这样的数据元素不存在,则返回值为0
- int LocateElem(LinkList L,ElemType e,int(*compare)(ElemType,ElemType))
- {
- int i=0;
- LinkList p=L->next;
- while(p) //将链表的每一个元素进行对比
- {
- i++;
- if(compare(p->data,e)) // 找到这样的数据元素
- return i;
- p=p->next;
- }
- return 0;
- }
- // 若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,// 返回1;否则操作失败,pre_e无定义,返回-1
- int PriorElem(LinkList L,ElemType cur_e,ElemType *pre_e)
- {
- LinkList q,p=L->next; // p指向第一个结点
- while(p->next) // p所指结点有后继
- {
- q=p->next; // q为p的后继
- if(q->data==cur_e)
- {
- *pre_e=p->data;
- return 1;
- }
- p=q; // p向后移
- }
- return -1;
- }
- // 若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,
- // 返回1;否则操作失败,next_e无定义,返回-1
- int NextElem(LinkList L,ElemType *next_e)
- {
- LinkList p=L->next; // p指向第一个结点
- while(p->next) // p所指结点有后继
- {
- if(p->data==cur_e)
- {
- *next_e=p->next->data;
- return 1;
- }
- p=p->next;
- }
- return -1;
- }
- // 在带头结点的单链线性表L中第i个位置之前插入元素e
- int ListInsert(LinkList *L,ElemType e)
- {
- int j=0;
- LinkList p=*L,s;
- while(p && j<i-1) // 寻找第i-1个结点
- {
- p=p->next;
- j++;
- }
- if(!p || j>i-1) // i小于1或者大于表长
- return 0;
- s=(LinkList)malloc(sizeof(struct LNode)); // 生成新结点
- s->data=e; // 插入L中
- s->next=p->next;
- p->next=s;
- return 1;
- }
- // 在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
- int ListDelete(LinkList *L,ElemType *e)
- {
- int j = 0;
- LinkList p=*L,q;
- while(p->next&&j<i-1) // 寻找第i个结点,并令p指向其前趋
- {
- p=p->next;
- j++;
- }
- if(!p->next||j>i-1) // 删除位置不合理
- return 0;
- q=p->next; // 删除并释放结点
- p->next=q->next;
- *e=q->data;
- free(q);
- return 1;
- }
- // 依次对L的每个数据元素调用函数vi()
- int ListTraverse(LinkList L,void(*vi)(ElemType))
- {
- LinkList p=L->next;
- //对所有元素调用函数vi
- while(p)
- {
- vi(p->data);
- p=p->next;
- }
- printf("\n");
- return 1;
- }
- // 在按非降序排列的线性表L中按非降序插入新的数据元素e
- void InsertAscend(LinkList L,ElemType e)
- {
- LinkList q=L,p=L->next;
- while(p&&e>p->data)
- {
- q=p;
- p=p->next;
- }
- q->next=(LinkList)malloc(sizeof(struct LNode)); // e插在q后
- q->next->data=e;
- q->next->next=p;
- }
- // 按非升序排列的线性表L中按非升序插入新的数据元素e
- void InsertDescend(LinkList L,p=L->next;
- while(p&&e<p->data)
- {
- q=p;
- p=p->next;
- }
- q->next=(LinkList)malloc(sizeof(struct LNode)); // e插在q后
- q->next->data=e;
- q->next->next=p;
- }
- // L的头部插入新的数据元素e,作为链表的第一个元素
- int HeadInsert(LinkList L,ElemType e)
- {
- LinkList s;
- s=(LinkList)malloc(sizeof(struct LNode)); // 生成新结点
- s->data=e; // 给结点赋值
- s->next=L->next; // 插在表头
- L->next=s;
- return 1;
- }
- // 在L的尾部插入新的数据元素e,作为链表的最后一个元素
- int EndInsert(LinkList L,ElemType e)
- {
- LinkList p=L;
- while(p->next) // 使p指向表尾元素
- p=p->next;
- p->next=(LinkList)malloc(sizeof(struct LNode)); // 在表尾生成新结点
- p->next->data=e; // 给新结点赋值
- p->next->next=NULL; // 表尾
- return 1;
- }
- // 删除L的第一个数据元素,并由e返回其值
- int DeleteFirst(LinkList L,ElemType *e)
- {
- LinkList p=L->next;
- if(p)
- {
- *e=p->data;
- L->next=p->next;
- free(p);
- return 1;
- }
- else
- return 0;
- }
- // 删除L的最后一个数据元素,并用e返回其值
- int DeleteTail(LinkList L,ElemType *e)
- {
- LinkList p=L,q;
- if(!p->next) // 链表为空
- return 0;
- while(p->next)
- {
- q=p;
- p=p->next;
- }
- q->next=NULL; // 新尾结点的next域设为NULL
- *e=p->data;
- free(p);
- return 1;
- }
- // 删除表中值为e的元素,并返回1;如无此元素,则返回0
- int DeleteElem(LinkList L,ElemType e)
- {
- LinkList p=L,q;
- while(p)
- {
- q=p->next;
- if(q&&q->data==e)
- {
- p->next=q->next;
- free(q);
- return 1;
- }
- p=q;
- }
- return 0;
- }
- // 用e取代表L中第i个元素的值
- int ReplaceElem(LinkList L,ElemType e)
- {
- LinkList p=L;
- int j=0;
- //找到第i个元素的位置给p
- while(p->next && j<i)
- {
- j++;
- p=p->next;
- }
- if(j==i)
- {
- p->data=e;
- return 1;
- }
- else // 表中不存在第i个元素
- return 0;
- }
- // 按非降序建立n个元素的线性表
- int CreatAscend(LinkList *L,int n)
- {
- int j;
- LinkList p,q,s;
- if(n<=0)
- return 0;
- InitList(L);
- printf("请输入%d个元素:(空格)\n",n);
- s=(LinkList)malloc(sizeof(struct LNode)); // 第一个结点
- scanf("%d",&s->data);
- s->next=NULL;
- (*L)->next=s;
- for(j=1;j<n;j++)
- {
- s=(LinkList)malloc(sizeof(struct LNode)); // 其余结点
- scanf("%d",&s->data);
- q=*L;
- p=(*L)->next;
- while(p&&p->data<s->data) // p没到表尾,且所指元素值小于新值
- {
- q=p;
- p=p->next; // 指针后移
- }
- s->next=q->next; // 元素插在q的后面
- q->next=s;
- }
- return 1;
- }
- // 按非升序建立n个元素的线性表
- int CreatDescend(LinkList *L,&s->data);
- q=*L;
- p=(*L)->next;
- while(p&&p->data>s->data) // p没到表尾,且所指元素值大于新值
- {
- q=p;
- p=p->next; // 指针后移
- }
- s->next=q->next; // 元素插在q的后面
- q->next=s;
- }
- return 1;
- }
- // 返回表头元素的值
- int GetFirstElem(LinkList L,ElemType *e)
- {
- LinkList p=L->next; //第一个结点给p
- if(!p) // 空表
- return 0;
- else // 非空表
- *e=p->data;
- return 1;
- }
- // 逆位序(插在表头)输入n个元素的值,建立带表头结构的单链线性表L
- void CreateList(LinkList *L,int n)
- {
- int i;
- LinkList p;
- // 先建立一个带头结点的空单链表,相当于初始化单链表
- *L=(LinkList)malloc(sizeof(struct LNode));
- (*L)->next=NULL;
- printf("请输入%d个数据\n",n);
- for(i=n;i>0;--i)
- {
- p=(LinkList)malloc(sizeof(struct LNode)); // 生成新结点
- scanf("%d",&p->data); // 输入元素值
- p->next=(*L)->next; // 插入到表头
- (*L)->next=p;
- }
- }
- // 正位序(插在表尾)输入n个元素的值,建立带表头结构的单链线性表
- void CreateList2(LinkList *L,int n)
- {
- int i;
- LinkList p,q;
- // 先建立一个带头结点的空单链表,相当于初始化单链表
- *L=(LinkList)malloc(sizeof(struct LNode)); // 生成头结点
- (*L)->next=NULL;
- q=*L;
- printf("请输入%d个数据\n",n);
- for(i=1;i<=n;i++)
- {
- p=(LinkList)malloc(sizeof(struct LNode));
- scanf("%d",&p->data);
- q->next=p;
- q=q->next;
- }
- p->next=NULL;
- }
- // 已知单链线性表La和Lb的元素按值非递减排列。
- // 归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列
- void MergeList(LinkList La,LinkList *Lb,LinkList *Lc)
- {
- LinkList pa=La->next,pb=(*Lb)->next,pc;
- *Lc=pc=La; // 用La的头结点作为Lc的头结点
- while(pa&&pb)
- {
- if(pa->data <= pb->data)
- {
- pc->next=pa;
- *Lc=pa;
- pa=pa->next;
- }
- else
- {
- pc->next=pb;
- pc=pb;
- pb=pb->next;
- }
- }
- pc->next=pa ? pa : pb; // 插入剩余段
- free(*Lb); // 释放Lb的头结点
- Lb=NULL;
- }
- // 判断是否相等的函数,Union()用到
- int equal(ElemType c1,ElemType c2)
- {
- if(c1==c2)
- return 1;
- else
- return 0;
- }
- // 将所有在线性表Lb中但不在La中的数据元素插入到La中
- void Union(LinkList La,LinkList Lb)
- {
- ElemType e;
- int La_len,Lb_len;
- int i;
- La_len=ListLength(La); // 求线性表的长度
- Lb_len=ListLength(Lb);
- for(i=1;i<=Lb_len;i++)
- {
- GetElem(Lb,i,&e); // 取Lb中第i个数据元素赋给e
- if(!LocateElem(La,e,equal)) // La中不存在和e相同的元素,则插入之
- ListInsert(&La,++La_len,e);
- }
- }
- // 数据元素判定函数(相等为1,否则为0)
- int comp(ElemType c1,ElemType c2)
- {
- if(c1==c2)
- return 1;
- else
- return 0;
- }
- void visit(ElemType c)
- {
- printf("%d ",c);
- }
- int main()
- {
- LinkList L,La,Lb,Lc;
- ElemType e,e0,d;
- int i,j,n,k;
- //初始化一个单链表
- i=InitList(&L);
- //通过插入操作创建一个单链表
- for(j=1;j<=5;j++)
- i=ListInsert(&L,1,j);
- //调用visit函数,对单链表进行遍历
- printf("在L的表头依次插入1~5后:L=");
- ListTraverse(L,visit); // 依次对元素调用visit(),输出元素的值
- //判断单链表是否为空
- i=ListEmpty(L);
- printf("L是否空:i=%d(1:是 0:否)\n",i);
- //清空单链表
- i=ClearList(L);
- printf("清空L后:L=");
- ListTraverse(L,visit);
- //判断单链表是否为空
- i=ListEmpty(L);
- printf("L是否空:i=%d(1:是 0:否)\n",i);
- //再次通过插入操作创建一个单链表
- for(j=1;j<=10;j++)
- ListInsert(&L,j);
- printf("在L的表尾依次插入1~10后:L=");
- ListTraverse(L,visit);
- //取得单链表的第5个元素
- GetElem(L,5,&e);
- printf("第5个元素的值为:%d\n",e);
- //在单链表中找到和j满足comp函数关系的元素
- for(j=0;j<=1;j++)
- {
- k=LocateElem(L,comp);
- if(k)
- printf("第%d个元素的值为%d\n",k,j);
- else
- printf("没有值为%d的元素\n",j);
- }
- //找到某个元素的前驱
- for(j=1;j<=2;j++) // 测试头两个数据
- {
- GetElem(L,&e0); // 把第j个数据赋给e0
- i=PriorElem(L,&e); // 求e0的前驱
- if(i==-1)
- printf("元素%d无前驱\n",e0);
- else
- printf("元素%d的前驱为:%d\n",e);
- }
- //找到某个元素的后继
- for(j=ListLength(L)-1;j<=ListLength(L);j++)// 测试最后两个数据
- {
- GetElem(L,&e0); // 把第j个数据赋给e0
- i=NextElem(L,&e); // 求e0的后继
- if(i==-1)
- printf("元素%d无后继\n",e0);
- else
- printf("元素%d的后继为:%d\n",e);
- }
- //求单链表的表长
- k=ListLength(L); // k为表长
- //删除操作
- for(j=k+1;j>=k;j--)
- {
- i=ListDelete(&L,&e); // 删除第j个数据
- if(i==0)
- printf("删除第%d个数据失败\n",j);
- else
- printf("删除的元素为:%d\n",e);
- }
- printf("依次输出L的元素:");
- ListTraverse(L,visit);
- //销毁单链表
- DestroyList(&L);
- printf("销毁L后:L=%u\n\n",L);
- printf("按非降序建立n个元素的线性表L,请输入元素个数n: ");
- scanf("%d",&n);
- CreatAscend(&L,n);
- printf("依次输出L的元素:");
- ListTraverse(L,visit);
- // 按非降序插入元素10
- InsertAscend(L,10);
- printf("按非降序插入元素10后,线性表L为:");
- ListTraverse(L,visit);
- // 在L的头部插入12
- HeadInsert(L,12);
- // 在L的尾部插入9
- EndInsert(L,9);
- printf("在L的头部插入12,尾部插入9后,线性表L为:");
- ListTraverse(L,visit);
- i=GetFirstElem(L,&e);
- printf("第1个元素是: %d\n",e);
- printf("请输入要删除的元素的值: ");
- scanf("%d",&e);
- i=DeleteElem(L,e);
- if(i)
- printf("成功删除%d!\n",e);
- else
- printf("不存在元素%d!\n",e);
- printf("线性表L为:");
- ListTraverse(L,visit);
- printf("请输入要取代的元素的序号 元素的新值: ");
- scanf("%d%d",&n,&e);
- ReplaceElem(L,visit);
- DestroyList(&L);
- printf("销毁L后,按非升序重新建立n个元素的线性表L,请输入"
- "元素个数n(>2): ");
- scanf("%d",&n);
- CreatDescend(&L,visit);
- // 按非升序插入元素10
- InsertDescend(L,10);
- printf("按非升序插入元素10后,线性表L为:");
- ListTraverse(L,visit);
- printf("请输入要删除的元素的值: ");
- scanf("%d",visit);
- DeleteFirst(L,&e);
- DeleteTail(L,&d);
- printf("删除表头元素%d和表尾元素%d后,线性表L为:",d);
- ListTraverse(L,visit);
- printf("\n");
- // 测试算法2.11
- n = 3;
- CreateList2(&La,n); // 正位序输入n个元素的值
- printf("正位创建后La="); // 输出链表La的内容
- ListTraverse(La,visit);
- CreateList(&Lb,n); // 逆位序输入n个元素的值
- printf("逆位创建后Lb="); // 输出链表Lb的内容
- ListTraverse(Lb,visit);
- DestroyList(&La);
- DestroyList(&Lb);
- // 测试算法2.12
- //初始化一个单链表La
- i=InitList(&La);
- //通过插入操作创建一个单链表
- for(j=2;j<=10;j+=2)
- i=ListInsert(&La,j);
- printf("La="); // 输出链表La的内容
- ListTraverse(La,visit);
- //初始化一个单链表
- i=InitList(&Lb);
- //通过插入操作创建一个单链表
- for(j=1;j<=10;j+=2)
- i=ListInsert(&Lb,j);
- printf("Lb="); // 输出链表Lb的内容
- ListTraverse(Lb,visit);
- // 按非递减顺序归并La和Lb,得到新表Lc
- MergeList(La,&Lb,&Lc);
- printf("合并La和Lb后,Lc = "); // 输出链表Lc的内容
- ListTraverse(Lc,visit);
- // 测试算法2.1
- i=InitList(&La);
- if(i==1) // 创建空表La成功
- for(j=1;j<=5;j++) // 在表La中插入5个元素
- i=ListInsert(&La,j);
- printf("La= "); // 输出表La的内容
- ListTraverse(La,visit);
- InitList(&Lb); // 也可不判断是否创建成功
- for(j=1;j<=5;j++) // 在表Lb中插入5个元素
- i=ListInsert(&Lb,2*j);
- printf("Lb= "); // 输出表Lb的内容
- ListTraverse(Lb,visit);
- Union(La,Lb);
- printf("new La= "); // 输出新表La的内容
- ListTraverse(La,visit);
- system("pause");
- return 0;
- }
- /*
- 输出效果:
- 在L的表头依次插入1~5后:L=5 4 3 2 1
- L是否空:i=0(1:是 0:否)
- 清空L后:L=
- L是否空:i=1(1:是 0:否)
- 在L的表尾依次插入1~10后:L=1 2 3 4 5 6 7 8 9 10
- 第5个元素的值为:5
- 没有值为0的元素
- 第1个元素的值为1
- 元素1无前驱
- 元素2的前驱为:1
- 元素9的后继为:10
- 元素10无后继
- 删除第11个数据失败
- 删除的元素为:10
- 依次输出L的元素:1 2 3 4 5 6 7 8 9
- 销毁L后:L=0
- 按非降序建立n个元素的线性表L,请输入元素个数n: 3
- 请输入3个元素:(空格)
- 1 3 2
- 依次输出L的元素:1 2 3
- 按非降序插入元素10后,线性表L为:1 2 3 10
- 在L的头部插入12,尾部插入9后,线性表L为:12 1 2 3 10 9
- 第1个元素是: 12
- 请输入要删除的元素的值: 1
- 成功删除1!
- 线性表L为:12 2 3 10 9
- 请输入要取代的元素的序号 元素的新值: 3 4
- 线性表L为:12 2 4 10 9
- 销毁L后,请输入元素个数n(>2): 3
- 请输入3个元素:(空格)
- 1 3 2
- 依次输出L的元素:3 2 1
- 按非升序插入元素10后,线性表L为:10 3 2 1
- 请输入要删除的元素的值: 3
- 成功删除3!
- 线性表L为:10 2 1
- 删除表头元素10和表尾元素1后,线性表L为:2
- 请输入3个数据
- 1 3 2
- 正位创建后La=1 3 2
- 请输入3个数据
- 1 3 2
- 逆位创建后Lb=2 3 1
- La=10 8 6 4 2
- Lb=9 7 5 3 1
- 合并La和Lb后,Lc = 9 7 5 3 1 10 8 6 4 2
- La= 1 2 3 4 5
- Lb= 2 4 6 8 10
- new La= 1 2 3 4 5 6 8 10
- 请按任意键继续. . .
- */