1、线性表的链式存储结构:n个结点(结点存数据元素和后继元素的指针),链接为一个链表,即为线性表(a1,a2,……,an)的链式存储结构。
2、链式存储结构的头指针:①头指针是链表的必要元素!!无论链表是否为空,头指针均不为空。②头指针有标识作用,通常用来标识链表名。③头指针指向链表的第一个结点(头结点或第一个结点)。
3、头结点:①头结点不是必须的。②头结点是为了第一个元素前的插入或删除和后面元素一样,而设立的。放在第一个结点之前。数据域一般无意义,不过也可以存放链表长度。
4线性表的顺序存储结构和链式存储结构的对比:
5、链式存储结构代码(以单链表为例)
/************************************************************************/
/* (2)线性链式存储 */
/************************************************************************/
#include <stdio.h>
#include <time.h>
#include <iostream>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MaxSize 30 //存储空间初始分配量
typedef int Status;
typedef int ElemType;
extern Status visit(ElemType c);
/* 线性表的单链表存储结构 */
typedef struct Node //①定义Node结点:数据域+后继结点地址的指针域;
{
ElemType data;
struct Node *next;
}Node; //②typedef struct Node Node:Node可替换为 struct Node
typedef struct Node *LinkList; //定义LinkList链表,LinkList 可替换为 struct Node *
//初始化顺序线性表
Status InitList(LinkList *L)
{
*L=(LinkList)malloc(sizeof(Node)); //产生头结点,并使L指向此头结点
if(!(*L)) //存储分配失败
return ERROR;
(*L)->next =NULL; //令头结点的指针域为空
return OK;
}
/* 初始条件:顺序线性表L已经存在 */
/* 操作结果:若L为空表,则返回TRUE,否则返回FALSE */
Status ListEmpty(LinkList L)
{
if (L->next == NULL)
return TRUE;
else
return FALSE;
}
/* 初始条件:顺序线性表L已经存在 */
/* 操作结果:将L重置为空表 */
Status ClearList(LinkList L)
{
LinkList p,q;
p=(*L).next; //p指向第一个节点
while(p) //若p不为空,表示还没到表尾,一直while循环
{
q=p->next;
free(p); //释放每一个结点所占的内存空间
p=q;
}
(*L).next = NULL; // 将头结点指针域置为空
return OK;
}
/* 初始条件:顺序线性表L已经存在 */
/* 操作结果:返回L中数据元素的个数*/
int ListLength(LinkList L)
{
int k=0;
LinkList p=L->next; //p指向L表的第一个结点
while(p)
{
k++;
p=p->next;
}
return k;
}
/* 初始条件:顺序线性表已经存在,且1<=i<=LineList(L) */
/* 操作结果:用e返回L中第i个数据元素的值 */
Status GetElem(LinkList L, int i,ElemType *e)
{
int j;
LinkList p; //声明一个结点p
p=L->next; //p指向链表的第一个结点
j=1;
while(p && j<i)
{
p=p->next;
j++;
}
if (!p || j>i) //如果p为空,或j>i,则第i个元素不存在
return ERROR;
*e = p->data; //否则,第i个数据存在,取出即可
return OK;
}
/* 初始条件:顺序线性表L已经存在 */
/* 操作结果:返回L中第1个与e满足关系的数据元素的位序*/
int LocateElem(LinkList L,ElemType e)
{
int i=0;
LinkList p=L->next;
while(p)
{
i++;
if (e==p->data)
return i;
else
p=p->next;
}
return 0;
}
/* 初始条件:顺序线性表L已经存在 */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p=*L;
j=1;
while(p && j<i)
{
j++;
p=p->next;
}
if (!p || j>i)
return ERROR; //第i个元素不存在
s = (LinkList) malloc(sizeof(Node)); //生成新结点
s->data =e;
s->next=p->next;
p->next =s;
return OK;
}
/* 初始条件:线性顺序表L已经存在 */
/* 操作结果:删除L的第i个位置的数据元素,并用e返回其值,L的长度减1*/
Status ListDelete(LinkList *L,int i,ElemType *e)
{
int j;
LinkList p,q;
p=*L;
j=1;
while(p->next && j<i)
{
j++;
p=p->next;
}
if (!(p->next) || j>i)
return ERROR;
q=p->next;
p->next=q->next;
*e=q->data;
free(q); //系统回收该结点,释放内存
return OK;
}
/* 初始条件:顺序线性表L已经存在 */
/* 操作结果:依次对L的每个元素输出*/
Status ListTraverse(LinkList L)
{
LinkList p=L->next; //p指向第一个结点
while(p)
{
visit(p->data);
p=p->next;
}
printf("\n");
return OK;
}
/*随机产生n个元素的值,建立带表头结点的单链线性表L(头插法)*/
void CreateListHead(LinkList *L,int n)
{
LinkList p;
int i;
srand(time(0)); //srand:产生随机数,初始化随机数种子
*L=(LinkList) malloc(sizeof(Node)); //这句和下句,是生成一个新结点表示头结点,指向NULL表示只有头结点
(*L)->next=NULL; //先建立一个带头结点的单链表
for (i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node)); //生成新的结点
p->data=rand()%100+1;
p->next=(*L)->next; //令p->next=NULL,从表头插入
(*L)->next = p; //插入到表头
}
}
/* 尾插法 */
void CreateListTail(LinkList *L,int n)
{
LinkList p,r;
srand(time(0));
*L = (LinkList)malloc(sizeof(Node));
r=(*L);
for(int i=0;i<n;i++)
{
p=(LinkList)malloc(sizeof(Node));
p->data=rand()%100+1;
r->next=p;
r=p; //将当前新结点定义为表最终端的结点
}
r->next=NULL;
}
int main()
{
LinkList L;
ElemType e;
Status i;
int j,k;
i=InitList(&L);
printf("初始化链表L后,ListLength(L)=%d\n",ListLength(L));
for (j=1;j<=5;j++)
{
i=ListInsert(&L,1,j);
}
printf("在表头依次插入1~5之后:L.data=");
ListTraverse(L);
printf("ListLength(L)=%d\n",ListLength(L));
i=ListEmpty(L);
printf("L是否为空:i=%d(1:是;0:否)",i);
printf("\n");
i=ClearList(L);
i=ListEmpty(L);
printf("ClearList之后,L是否为空:i=%d(1:是;0:否)",i);
printf("\n");
for (j=1;j<=10;j++)
{
ListInsert(&L,j,j);
}
printf("在L的表尾依次插入1~10之后,L.data=");
ListTraverse(L);
printf("ListLength(L)=%d",ListLength(L));
GetElem(L,5,&e);
printf("第5个元素为:%d\n",e);
for(j=3;j<=4;j++)
{
k=LocateElem(L,j);
if(k)
printf("第%d个元素值为%d\n",k,j);
else
printf("没有值为%d的元素\n",j);
}
k=ListLength(L);
printf("k=ListLength(L)=%d\n",k);
for(j=k+1;j>=k;j--)
{
i=ListDelete(&L,j,&e); //删除第j个数
if (i == ERROR)
printf("删除第%d个数据失败\n",j);
else
printf("要删除的第%d个数据为:%d",j,e);
}
printf("依次输出L中的元素:");
ListTraverse(L);
j=5;
ListDelete(&L,j,&e);
printf("要删除的第%d个数据为%d",j,e);
printf("依次输出L中的元素:");
ListTraverse(L);
i=ClearList(L);
printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
CreateListHead(&L,5);
printf("头插法:");
ListTraverse(L);
i=ClearList(L);
printf("\n清空L后:ListLength(L)=%d\n",ListLength(L));
CreateListTail(&L,5);
printf("尾插法:");
ListTraverse(L);
getchar();
}