采用链式存储结构的线性表称为线性链表。结点包含数据域和指针域两部分。链表明指向第一个结点(头指针),尾结点指针域值为NULL。
定义的辅助宏:
#define OK 1
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define NULL 0
#define OVERFLOW -1
typedef int ElemType;//假设链表中的元素均为整型
typedef int Status;
链表的存储结构定义
//链表的存储结构定义
typedef struct LNode{
ElemType data; //数据域
struct LNode * next; //指针域
}LNode,*LinkList;
初始化L为一个空的有序链表:
Status InitList_L(LinkList &L) {
//初始化L为一个空的有序链表
L=(LNode *)malloc(sizeof(LNode));
if(L==NULL)
exit(OVERFLOW);
L->next=NULL;
return OK;
}
在链表L的第i个位置前插入元素e,i的合法值为1..L.length
Status ListInsert_L(LinkList &L,int i,ElemType e){
//在链表L的第i个位置前插入元素e,i的合法值为1..L.length
//定位到第i-1个结点,在其后插入一个新开辟的结点,注意i异常。
LNode *p=L; //p始终指向第j个结点
int j=0;
while(p&&j<i-1) {//T(n)=O(n); 只要不空且味道第i-1个
p=p->next;
j++;
}
if(!p||i<1)//插入位置不合法,第i-1个结点不存在或者i<1
return ERROR;
LNode *q;
q=(LNode *)malloc(sizeof(LNode));
if(!q)
exit(OVERFLOW);
q->data=e;
q->next=p->next;
p->next=q;
return OK;
}
依次输出有序链表L中的各个元素.
void OutputElem(ElemType e){
printf("%d\n",e);
}
void ListPrint_L(LinkList &L){
//依次输出有序链表L中的各个元素
if(L->next==NULL)
printf("空表");
else{
LNode *p=L->next;
while(p){ //T(n)=O(n);
OutputElem(p->data);
p=p->next;
}
}
}
销毁有序链表L.
Status DestroyList_L(LinkList &L){
//销毁有序链表L
LNode *p=L,*q;
while(p){
q=p->next;
free(p);
p=q;
}
return OK;
}
链表置空.
Status ClearList_L(LinkList &L){
//链表置空
LNode *p=L->next,*q;
while(p){
q=p->next;
free(p);
p=q;
}
L->next=NULL;
return OK;
}
用e带回L中第i个元素的值并返回OK,i介于1与L.length之间,否则返回ERROR.
Status GetElem_L(LinkList &L,int i,ElemType &e){
//用e带回L中第i个元素的值并返回OK,i介于1与L.length之间,否则返回ERROR
//L为带头结点的单链表的头指针。第i个元素存在时,设遍历指针与相应计数器,
//从头开始后移至计数器为i停。i异常
LNode *p=L; //p指向第0个元素结点,j是该结点的位序
int j=0;
while(p&&j<i){ //顺序查找。只要p不空且未到第i结点就前进
p=p->next;
j++;
}
if(i<1||!p) //第i个结点不存在或者i<1
return ERROR;
e=p->data; //取第i个元素
return OK;
}
更新第i个元素结点的值为e,若i不合法则返回ERROR.
Status PutElem_L(LinkList &L,int i,ElemType e){
//更新第i个元素结点的值为e,若i不合法则返回ERROR
LNode *p=L;
int j=0;
while(p&&j<i){
p=p->next;
j++;
}
if(i<1||!p)
return ERROR;
p->data=e;
return OK;
}
删除L中第i个元素并用e带回,i介于1与表长之间.
Status ListDelete_L(LinkList &L,int i,ElemType &e){
//删除L中第i个元素并用e带回,i介于1与表长之间
//寻找第i-1个结点,若其后继结点存在则带回其data并删除
LNode *p=L,*q; //p始终指向第j个结点
int j=0;
while(p&&j<i-1){ //寻找第i-1个结点
p=p->next;
j++;
} //j最终为i-1,除非p空
if(i<1||!(p->next)||!p) //第i个或更前结点不存在
return ERROR;
q=p->next;
p->next=q->next;
e=q->data;
free(q);
return OK;
}
判断表空
bool ListEmpty_L(LinkList &L){
//判断表空
LNode *p=L;
if(!p->next)
return TRUE;
return FALSE;
}
返回表长.
int ListLength_L(LinkList &L){
//返回表长
int i=0;
LNode *p=L;
while(p->next){
p=p->next;
i++;
}
return i;
}
返回L中第一个与元素e满足关系cmp()的元素的位序,若不存在则返回0.
Status compare(ElemType e1,ElemType e2){
return e1==e2;
}
int LocateElem_L(LinkList &L,ElemType e,Status (*compare)(ElemType,ElemType)){
//返回L中第一个与元素e满足关系cmp()的元素的位序,若不存在则返回0
int i=0;
LNode *p=L->next;
while(p){
i++;
if(compare(p->data,e))
return i;
p=p->next;
}
return 0;
}
若cur_e是L中的元素且不是第一个,就返回他的前驱,否则pre_e未定义 操作失败.
Status PriorElem_L(LinkList &L,ElemType cur_e,ElemType &pre_e){
//求前驱
LNode *p=L;
int i=0;
while(p->next){
if(p->next->data==cur_e&&i!=0){
pre_e=p->data;
return OK;
}
i++;
p=p->next;
}
return ERROR;
}
若cur_e是L中的元素且不是最后一个,就返回他的后驱,否则pre_e未定义 操作失败.
Status NextElem_L(LinkList &L,ElemType cur_e,ElemType &pre_e){
//求后驱
LNode *p=L->next;
while(p){
if(p->data==cur_e&&p->next) {
pre_e=p->next->data;
return OK;
}
p=p->next;
}
return ERROR;
}
对每个数据调用visit()。
Status ListTraverse_L(LinkList &L,int (*visit)(ElemType &)){
//对每个数据调用visit()
LNode *p=L->next;
while(p){
visit(p->data);
p=p->next;
}
return OK;
}
逆位序创建n个结点链表.
void IntputElem(ElemType &e) {
scanf("%d",&e);
}
Status CreatList_L(LinkList &L,int n){
//逆位序创建n个结点链表
//开辟头结点并初始化。循环n次,每次新开辟一个结点放到头后
L=(LNode *)malloc(sizeof(LNode));
if(!L)
exit(OVERFLOW);
L->next=NULL;
LNode *p;
for(int i=0;i<n;i++){
p=(LNode *)malloc(sizeof(LNode));
IntputElem(p->data);
p->next=L->next;
L->next=p;
}
return OK;
}
删除大于mink小于maxk的值.
void ListPartDel_Sorted(LinkList &L,ElemType mink,ElemType maxk){
//删除大于mink小于maxk的值
//首先定位第一个大于等于mink的元素,循环{从其开始删除,直到遇到大于
//maxk的停止}
//preq最初指向头结点 p最初指向第一个元素结点,后文中preq始终指向p的前驱
LNode *p=L->next,*prep=L;
while(p&&p->data<mink) {
prep=prep->next;
p=p->next;
}//移动指针使指向第一个符合条件元素
//说明链表元素均小于mink
if(!p)
return;
while(p&&p->data<=maxk){ //移动指针判断是否符合条件,是就删除
prep->next=p->next;
free(p);
p=prep->next;
}
}
实现有头结点的链表的就地逆置.
Status ListInverse(LinkList &L){
//实现有头结点的链表的就地逆置
//令指针p指向首源节点,头结点与元素结点断开,用指针变量
//p一次遍历各个元素结点,每次都将当前元素结点放到头结点的后面
LNode *p=L->next,*q;
L->next=NULL;
while(p) { //把第一个结点后的结点依次插入到第一个位置,即可实现逆置
q=p->next; //令q指向p的后继结点,以便以后p后移
p->next=L->next; //接下来两句将p所指向结点插入到头结点后
L->next=p;
p=q; //q后移
}
return OK;
}
递归遍历每个数据:
void ListTraverse(LinkList L){
//递归遍历每个数据:
if(!L->next)
return;
else {
printf("%d\n",L->next->data);
ListTraverse(L->next);
}
}