我们首先用一个结构体定义链表的储存结构,代码如下。
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
/*-------------线性表的链式储存结构-----------------*/
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
typedef int Status;
在链表L中第i个元素之前插入一个新的元素:我们需要找到第i-1个结点,然后修改其指向后继的指针。假设新插入的元素e,新生成的结点为s,我们可以分为三个个步骤:1.让e的后继指向i-1的后继(也就是指向i),2.让i-1的后继的指针指向s,3.然后讲新插入的元素值赋给新插入结点的数据域。这样便插入了一个新的元素。代码如下:
Status ListInsert_L(LinkList *L,int i,ElemType e)/*在L中第i个元素之前插入新的元素e*/
{
LinkList p,s;
int j=0;
p=*L;
while(p&&j<i-1) /*寻找第i-1个节点*/
{
p=p->next;
++j;
}
if(!p||(j>i-1))return 0;/*i小于1或者大于表长加1*/
s=(LinkList)malloc(sizeof(LNode));/*生成新的节点*/
s->next=p->next;p->next=s;/*插入到L中*/
s->data=e;
return 1;
}
要想在链表L中删除第i个元素与插入元素的思路相同,找到第i-1个结点,然后修改其后继的指针。假设删除第i个结点,一个中间变量。1.我们首先找到第i-1个结点;2.q=p->next,p->next=q->next;这样i-1结点的后继指针便指向了i+1结点,我们可以然后删除q,便删除了第i个结点。代码如下:
Status ListDelete_L(LinkList *L,int i)/*删除L中第i个数据元素*/
{
LinkList p,q;
int j;
p=*L;j=0;
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;/*删除并释放结点*/
free(q);
return 1;
}
取出链表L中第i个元素的值:因为单链表是一种顺序储存结构,因此如果想要找到第i个元素首先需要找到第i-1个元素,
基本操作为移动指针,比较j和i,指针p始终指向链表中的第j个元素。代码如下:
Status GetElem_L(LinkList L,int i,ElemType *e)/*取出链表L中第i个元素的值*/
{
LinkList p;int j;
p=L;j=0;
while(p&&j<i) /*寻找第i个结点*/
{
p=p->next;++j;
}
if(!p||j>i)return 0;
*e=p->data; /*用来返回第i个结点的值*/
return 1;
}
查询链表L中与e元素相同的第一次出现的位序:我们可以遍历整个链表,找到元素后返回位序,并停止遍历;代码如下:
Status LocateElem_L(LinkList *L,ElemType e,int *n/*,compare()*/)/*查询链表中与e相同元素的第一个值*/
{ /*并用n返回其位置*/
LinkList p;
int j=0;
p=*L;
while(p)/*判断p是否为空*/
{
p=p->next;++j;
if(p->data==e)/*判断p所指向的数据的值是否与e相等*/
{
*n=j;return 1;
break;
}
}
return 0;
}
逆序插入法生成一个链表:和插入思想相同,生成头结点函数写在了主函数(测试函数与)中,最后会有说明。代码如下:
void CreateList_L(LinkList *L,int n)/*逆序输入n个元素的值,n为链表元素的个数*/
{
LinkList p,s;
p=*L;
for(n;n>0;--n)
{
int tmp;
s=(LinkList)malloc(sizeof(LNode));/*生成新的结点*/
scanf("%d",&tmp);
s->data=tmp; /*插入元素的值*/
s->next=p->next;p->next=s; /*插入到表头*/
}
}
输出链表所有的值:遍历链表所有元素并依次输出。代码如下:
Status ListTraverse(LinkList *L)/*用于输出链表的所有值*/
{
LinkList p;
p=*L;
p=p->next;/*让p指向第一个结点*/
while(p)/*判断p是否为空*/
{
printf("%d\t",p->data);/*输出元素的值,并让p指向下一个结点*/
p=p->next;
}
printf("\n");
return 0;
}
测试链表的长度:代码如下:
Status ListLenght_L(LinkList *L)/*用于测链表的长度*/
{
int j=0;
LinkList p=*L;
while(p)/*判断p是否为空*/
{
j++;
p=p->next;
}
return j;
}
接下来我们测试一下程序的运行结果,在测试程序中生成的链表元素个数为5,结点的个数(包含头结点)为6。1.输入的数据为11,12,13,14,15;2.逆序生成链表输出;3.在第四个元素之前插入“8”然后输出;4.删除第四个元素在输出;5.取出第二个元素的值;6.链表的长度;7.返回元素"11"的位序。代码如下:
void main()/*测试函数*/
{
int n,n1,ex;/*用n表示取出元素的值,n1表示测试链表的长度,ex表示第一个与元素e相等的位置*/
LinkList L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
printf("请输入5个元素,用来逆序生成链表:");
CreateList_L(&L,5);/*我们设置为5个元素*/
printf("生成的链表为:");
ListTraverse(&L);
ListInsert_L(&L,4,8);
printf("在第四个元素前面插入元素8:生成的链表为:");
ListTraverse(&L);
ListDelete_L(&L,4);/*删除第四个结点*/
printf("删除第四个元素生成的链表为:");
ListTraverse(&L);
GetElem_L(L,2,&n);/*取出第二个元素的值*/
printf("第二个元素的值为:%d\n",n);
n1=ListLenght_L(&L);/*用来求链表的长度*/
printf("链表的长度为:%d\n",n1);
if( LocateElem_L(&L,11,&ex))/*查找与元素11相同的位序*/
{
printf("与元素11相同的元素的位序为:%d\n",ex);
}
else
{
printf("与元素11相同的元素的位序为:查找失败");
}
system("pause");
}
运行结果如下:
总结:
优点:1.它是一种动态储存结构,整个储存空间供多链表共用;2.使用时不用预先分配空间;3.插入删除方便;
缺点:1.指针占用额外储存空间,;2.不能随机存取,查找速度慢;
-------------------------------------------------------------------------华丽分割线-----------------------------------------------------
学习数据结构链表后记录,有错误的欢迎指正。