链表的相关术语
- 结点:
| 数据元素的存储映像。由数据域和指针域两部分组成- 数据域:
| 存储数据元素信息的域称为数据域- 指针域:
| 存储直接后继存储位置的域称为指针域- 链表:
| n个结点由指针链组成一个链表,它是线性表的链式存储映像,称为线性表的链式存储结构- 头指针:
| 头指针是指向链表中第一个结点的指针。若链表设有头结点,则头指针所 | 指结点为线性表的头结点;若链表不设头结点,则头指针所指结点为该线| 性表的首元结点。- 头节点:
| 是在首元结点之前附设的一个结点,其指针域指向首元结点。头结点的数| 据域可以不存储任何信息,也可存储与数据元素类型相同的其他附加信息。- 首元结点:
| 是指链表中存储第一个数据元素a1的结点- 单链表、双链表和循环链表:
| 结点只有一个指针域的链表,称为单链表或线性链表
| 结点有两个指针域的链表,称为双链表
| 首尾相接的链表称为循环链表
单链表的定义和实现
定义:
链式存储结构:结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。
线性表的链式表示又称为非顺序映像或链式映像
链表的存储结构示意图有以下两种形式:
| 不带头结点
| 带头结点
常见问题
实现:
单链表的表示和实现
//- - - - - 单链表的存储结构- - - - -
typedef struct Lnode{ //声明结点的类型和指向结点的指针类型
ElemType data; //结点的数据域
struct Lnode *next; //结点的指针域
}LNode,*LinkList; //LinkList为指向结构体Lnode的指针类型
LNode *p=new LNode;
//初始化
Status InitList_L(LinkList &L){
L=new LNode;//或L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
return OK;
}
//取值
Status GetElem_L(LinkList L,int i,ElemType &e){ //获取线性表L中的某个数据元素的内容,通过变量e返回
p=L->next;//P指向第一个结点(首元结点)
int j=1;
while(p&&j<i){
p=p->next;
++j;
}
if(!p||j>i) return ERROR; //第i个元素不存在
e=p->data; //取第i个元素
return OK;
}
//查找
LNode *LocateElem(LinkList L,ElemType e){
//在线性表L中查找值为e的数据元素
//找到,则返回L中值为e的数据元素地址,查找失败返回NULL
p=L->next;
while(p&&p->data!=e)
p=p->next;
return p;
}
//插入
Status ListInsert_L(LinkList &L,int i,ElemType e){ //在L中第i个元素之前插入数据元素e
p=L;
int j=0;
while(p&&j<i-1){p=p->next;++j;}//寻找第i-1个结点,p指向i-1结点
if(!p||j>i-1)return ERROR; //i大于表长+1或者小于1,插入位置非法
LNode *s=new LNode;s->data=e; //生成新结点s,将结点s的数据域置为e
s->next=p->next; //将结点s插入L中
p->next=s;
return OK;
}
//删除
Status LisDelete_L(LinkList &L,int i,ElemType &e){ //
p=L;
int j=0;
while((p->next)&&(j<i-1)){
p=p->next;
++j;
}//寻找第i个结点,p指向其前驱
if(!(p->next)||j>i-1)return ERROR; //删除位置不合理
LNode *q=p->next; //临时保存被删结点的地址以备释放
p->next=q->next; //改变删除节点前驱结点的指针域
e=q->data; //保存删除节点的数据域
delete q; //释放删除节点的空间
return OK;
}
创建单链表
//头插法
void CreateList_H(LinkList &L,int n){
L=new LNode;
L->next=NULL; //先建立一个带头结点的单链表
for(int i=0;i<n;++i){
p=new LNode; //生成新结点p=(LNode*)malloc(sizeof(LNode));
cin>>p->data; //输入元素值 scanf(&p->data);
p->next=L->next; //插入到表头
L->next=p;
}
}
//后插法
void CreateList_R(LinkList &L,int n){//正位序输入n个元素的值,建立带表头结点的单链表L
L=new LNode;
L->next=NULL;
LNode *r=NULL;
r=L; //尾指针r指向头结点
for(int i=0;i<n;++i){
p=new LNode;
cin>>p->data; //生成新结点,输入元素值
p->next=NULL;
r->next=p; //插入到表尾
r=p; //r指向新的尾结点
}
}
头文件和重命名
#include<iostream>
using namespace std;
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef int SElemType;
typedef int ElemType;
函数调用测试
int main(){
LinkList L=NULL;
//(1)初始化一个线性表;
cout<<"初始化成功输出1:"<<InitList_L(L)<<endl;
//(2)创建一个包含n个正整数值的线性表(线性表的长度n和表中元素的值随机输入);
cout<<"创建一个包含n个正整数值的线性表(线性表的长度n和表中元素的值随机输入),输入n:";
int n=0;
cin>>n;
CreateList_R(L,n);
//(3)将一个数x插在第i个元素前(x和i在程序运行时随机输入);
cout<<"一个数x插在第i个元素前(x和i在程序运行时随机输入),输入x:";
int x=0;
cin>>x;
cout<<"输入i:";
int i=0;
cin>>i;
ListInsert_L(L,i,x);
//(4)删除第i个元素(i在程序运行时输入),并在删除结束后输出删除元素的值;
cout<<"删除第i个元素(i在程序运行时输入),并在删除结束后输出删除元素的值,输入i:";
int e=0;
i=0;
cin>>i;
LisDelete_L(L,i,e);
cout<<"删除的元素为:"<<e<<endl;
//(5)查找指定元素e是否在线性表中存在,若存在返回此元素的位序,否则返回0;
cout<<"找指定元素e是否在线性表中存在,若存在返回此元素的位序,否则返回0,输入e:";
e=0;
cin>>e;
cout<<"该元素位序为:"<<LocateElem_L(L,e)<<endl;
//(6)查找指定位置元素的值并输出;
cout<<"查找指定位置元素的值并输出,输入位置i:";
e=0;
i=0;
cin>>i;
GetElem_L(L,i,e);
cout<<"该位置元素为:"<<e<<endl;
//(7)输出线性表中所有元素。
cout<<"输出当前链表所有元素值:";
for(int i=1;i<=n;i++){
GetElem_L(L,i,e);
cout<<e;
}
return 0;
}