一、线性表的定义
线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素。存储其本身的信息和一个指示其直接后继的信息(即直接后继的存储位置)。这两部分信息组成数据元素的存储映像,称为结点。它包括两个域:其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域称为指针域。指针域中存储的信息称为指针或链。n个结点链结成一个链表,即为线性表的链式存储结构。
二、头指针和头结点的定义和区分
//线性表的单链表存储结构
struct LNode{
ElemType data;
LNode *next;
}LNode,*LinkList;
概念:假设L是LinkList型的变量,则L为单链表的头指针,它指向表中第一个结点。若L为NULL,则所表示的线性表为“空”表,其长度为0。有时候,我们在单链表的第一个结点之前附设一个结点,称之为头结点。头结点的数据域可以不存储任何信息,也可以存储线性表的长度等类的附加信息,头结点的指针域存储指向第一个结点的指针(即第一个元素结点的存储位置)。
区分:1、这个头指针的意义在于,在访问链表时,明确链表存储在什么位置(从何处开始访问),由于链表的特性(next指针),知道了头指针,那么整个链表的元素都能够被访问,也就是说头指针是必须存在的。
2、
struct LNode head, first;
head.next = &first;
这里的head是头结点,first是第一个元素结点。那这个时候头指针就不是头结点的指针域了。而是:
struct node *root = &head;
root指针才是头指针,是指向头结点的指针。
root->data = 0;
root->next = &first;
//上下两段代码等价
head.data = 0;
head.next = &first;
三、单链表的12个基本操作
- InitList(LinkList &L) 构造一个空的线性表
- ListInsert(LinkList &L,int i,ElemType e) 在带头结点的单链线性表L中第i个位置之前插入元素e
- ListTraverse(LinkList L,void (*visit)(ElemType )) 依次对L的每个数据元素调用函数visit(),visit()是模板函数,具体由main函数中指定
- ListEmpty(LinkList L) 若L为空表,则返回TRUE,否则返回FALSE
- ListLength(LinkList L) 返回L中数据元素的个数
- DestroyList(LinkList &L) 销毁线性表L
- ClearList(LinkList L) 将L重置为空表(只留下头指针和头结点) 线性表L的结构:L+头结点+头结点指向的单链表
- LocateElem(LinkList L,ElemType e, Status(* compare)(ElemType,ElemType)) 返回L中第1个与e满足关系compare()的数据元素的位序,若这样的数据元素不存在,则返回值为0 compare()是数据元素判定函数(满足为1,否则为0)
- GetElem(LinkList L,int i,ElemType &e) L为带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回ok,否则返回ERROR
- PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e) 若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,返回ok,否则操作失败,pre_e无定义,返回ERROR
- NextElem(LinkList L,ElemType cur_e,ElemType &next_e) 若cur_e是L的数据元素,且不是最后一个,则用next_e 返回它的后继,返回OK
- ListDelete(LinkList L,int i,ElemType &e) 不改变L 在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
#include<stdio.h>
#include<malloc.h>
#include<math.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int ElemType;
typedef int Status;
struct LNode{//线性表的单链表结构
ElemType data;
LNode *next;
};
typedef LNode *LinkList;
void InitList(LinkList &L){
//操作结果:构造一个空的线性表
L=(LinkList)malloc(sizeof(LNode));
if(!L)//存储分配失败
exit(OVERFLOW);
L->next=NULL;//头结点的指针域为空
}
Status ListInsert(LinkList &L,int i,ElemType e){
//在带头结点的单链线性表L中第i个位置之前插入元素e
int j=0;
LinkList s,p=L;//p指向头结点
while(p&&j<i-1){
j++;//计数器+1
p=p->next;//p指向下个结点
}
if(!p||j>i-1)
return ERROR;
s=(LinkList)malloc(sizeof(LNode));//生成新结点,以下将其插入L中
s->data=e;//将e赋给新结点
s->next=p->next;//新结点指向元第i个结点
p->next=s;//原第i-1个结点指向新结点
return OK;//插入成功
}
void print(ElemType e){
printf("%d ",e);
}
void ListTraverse(LinkList L,void (*visit)(ElemType )){
//初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数visit()
LinkList p=L->next;
while(p)//p所指结点存在
{
visit(p->data);//对p所指结点调用函数visit()
p=p->next;//p指向下一个结点
}
printf("\n");
}
Status ListEmpty(LinkList L){
//初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE
if(L->next)
return FALSE;
else
return TRUE;
}
int ListLength(LinkList L){
//初始条件:线性表L已存在。操作结果;返回L中数据元素的个数
LinkList p;
int i=0;//计数器初值为0
p=L->next;//p指向第1个结点
while(p){//未到表尾
i++;//计数器+1
p=p->next;//p指向下个结点
}
return i;
}
void DestroyList(LinkList &L){
//初始条件:线性表L已存在。操作结果:销毁线性表L
LinkList q;
while(L){//L指向的结点(非空)
q=L->next;//q指向现在线性表的首元结点
free(L);//释放现在线性表的头结点
L=q;//L指向现头结点
}
}
void ClearList(LinkList L){
//初始条件:线性表L已存在。操作结果:将L重置为空表(只留下头指针和头结点)
//线性表L的结构; L=头结点+头结点指向的单链表
LinkList p=L->next;//p指向第1个结点
L->next=NULL;//将头结点指针域为空,断开头结点和头结点指向的单链表
DestroyList(p);//销毁p所指的单链表
}
int LocateElem(LinkList L,ElemType e, Status(* compare)(ElemType,ElemType)){
//初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)
//操作结果:返回L中第1个与e满足关系compare()的数据元素的位序
//若这样的数据元素不存在,则返回值为0
int i=0;
LinkList p=L->next;//p指向第1个结点
while(p)//未到表尾
{
i++;
if(compare(p->data,e))//找到这样的数据元素
return i;
p=p->next;//p指向下一个结点
}
return 0;//满足关系的数据元素不存在
}
Status equal(ElemType c1,ElemType c2){
//判断是否相等的函数
if(c1==c2)
return TRUE;
else
return FALSE;
}
Status GetElem(LinkList L,int i,ElemType &e){
//L为带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回ok,否则返回ERROR
int j=1;//计数器初值为1
LinkList p=L->next;//p指向第1个结点
while(p&&j<i)
{
j++;
p=p->next;//p指向下一个结点
}
if(!p||j>i)
return ERROR;
e=p->data;//取第i个元素的值赋给e
return OK;
}
Status PriorElem(LinkList L,ElemType cur_e,ElemType &pre_e){
//初始条件:线性表L已存在
//操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,返回ok,否则操作失败,pre_e无定义,返回ERROR
LinkList q,p=L->next;
while(p->next){//p所指结点有后继
q=p->next;
if(q->data==cur_e)//p的后继为cur_e
{
pre_e=p->data;//将p所指元素的值赋给pre_e
return OK;//
}
p=q; //p的后继不为cur_e,p向后移
}
return ERROR;
}
Status NextElem(LinkList L,ElemType cur_e,ElemType &next_e){
//初始条件:线性表L已存在
//操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e 返回它的后继,返回OK
LinkList p=L->next;//p指向第一个结点
while(p->next) //p所指结点有后继
{
if(p->data==cur_e)//p所指结点的值为cur_e
{
next_e=p->next->data;
return OK;
}
p=p->next;//p指向下个结点
}
return ERROR;
}
Status ListDelete(LinkList L,int i,ElemType &e){// 不改变L
//在带头结点的单链线性表L中,删除第i个元素,并由e返回其值
int j=0;//计数器初值为0
LinkList q,p=L;//p指向头结点
while(p->next && j<i-1){
j++;
p=p->next;//p指向下一个结点
}
if(!p->next || j>i-1)//删除位置不合理
return ERROR;
q=p->next;
p->next=q->next;//待删除结点的前驱指向待删结点的后继
e=q->data;//将待删结点的值赋给e
free(q);//释放待删结点
return OK;//删除成功
}