一:
1:单链表:结点只有一个指针域的链表,称为单链表或线性链表。
单链表的表示:
typedef struct Node{//声明结点的类型和指向结点的指针类型
ElemType data;//结点的数据域
struct Node *next;// 结点的指针域
}Node,*LinkList; //LinkList为指向结构体Node的指针类型。
定义链表L: LinkList L;
定义结点指针p: Node *p
或者
LinkLIst p;
2:双链表:结点有两个指针域的链表,称为双链表。
3:循环单链表:首尾相连的链表。
4:头指针,头结点,首元结点。
5:如何表示空表?
(1):无头结点,头指针为空时表示空表。
(2):有头结点,当头结点的指针域为空表示空表。
6:在链表设置头结点有什么好处?
(1).便于首元结点的处理
首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无需进行特殊处理。
(2).便于空表和非空表的统一处理
无论链表是否为空,头指针都是指向头结点的的非空指针,因此空表和非空表的处理也就统一了。
7:头结点的数据域内装的是什么?
头结点的数据域可以为空,也可存放线性表的长度等附加信息,但此结点不能计入链表长度值。
8:链表(链式存储结构)的特点
(1):结点在存储器中位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻。
(2);访问时只能通过头指针进入链表,并通过每个结点的指针域一次向后扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等。
二:
1.单链表的基本操作:
(1)单链表的初始化:(带头结点的单链表)
即构造一个如图的空表:
算法步骤:
a:生成新结点做头结点,用头指针L指向头结点。
b: 将头结点的指针域置空。
算法描述:
Status InitList_L(LinkList &L){
L=new Node//L=(Linklist)malloc(sizeof(Node));
L->next=NULL;
return OK;
}
(2):判断单链表是否为空:
注:空表中无元素,称为空链表(头指针和头结点仍然在)
算法思路:判断头结点指针域是否为空:
int isEmpty(LinkList L){//若L为空表,则返回1,否则返回0
if(L->next)//非空
return 0;
else
return 1;
}
(3)单链表的销毁;链表销毁后不存在。
算法思路:从头指针开始,依次释放所有结点(包括清除头结点和头指针).
Status DestoryList_L(LinkList &L){
Node *p;//LinkList p;
while(L){
p=L;
L=L->next;
delete p;
}
return OK;
}
(4):清除链表
链表仍然存在,但链表中无元素,成为空链表(头结点和头指针仍存在);
算法思路:依次释放所有结点,并将头结点指针域设置为空。
Status ClearList(LinkList &L){//将L重置为空表
Node *p,q;//或LinkList p,q;
p=L->next;
while(p){ //没到表尾
q=p->next;
delete p;
p=q;
}
L->next=NULL;//头结点指针域为空。
return OK;
}
(5):求单链表的表长
int ListLength_L(LinkList L){//返回L中数据元素的个数。
LinkList p;
p=L->next;//p指向第一个结点。
i=0;
while(p){//遍历单链表,统计结点数。
i++;
p=p->next;
}
return i;
}
知识回顾:
(6)取值——取单链表中第i个元素的内容。
实现代码:
Status GetElem_l(LinkList L,int i,ElemType &e){
p=L->next;
j=1;
while(p&&j<i){
p=p->next;
++j;
}
if(!p||j>i) return ERROR;//第i个元素不存在。
e=p->data;//取第i个元素。
return OK;
} //GetElem L;
知识回顾:
(7)按值查找——根据指定数据获取数据所在的位置(地址)
实现代码:
Node* locateElem_L(LinkList L,Elemtype e){
//在线性表L中查询值为e的数据元素
//找到,则返回L中值为e的数据元素的地址,查找失败返回NULL
p=L->next;
while(p&&p->data!=e){
p=p->next;
}
return p;
}
(7)-1;按值查找——根据指定数据获取该数据的位置序号
算法实现:
//在线性表L中查找值为e的数据元素的位置序号。
int LocateElem_L(LinkList L,ElemType e){
//返回L中值为e的数据元素的位置序号,查找失败返回
p=L->next;j=1;
while(p&&p->data!=e){
p=p->next;
j++;
}
if(p) return j;
else return 0;
}
(8)插入——在第i个结点前插入值为e的新结点。
实现代码:
//在L中第i个元素之前插入数据元素e
Status ListInsert_L(LinkList&L ,int i,ElemType e){
LinkList P=L;
j=0;
while(p&&j<i-1){
p=p->next;//寻找第i-1个结点,p指向i-1结点。
++j;
}
if(!p||j>i-1) return ERROR; //i大于表长+1或者小于1,插入位置非法
s=new Node;//生成新结点s,
s->data=e; //将结点s的数据域置为e
return OK;
}
(9):删除第i个结点
代码实现:
//将线性表L中第i个数据元素删除。
Status ListDelete_L(LinkList &L,int i,ElemType &e){
p=L;
j=0;
while(p->next&&j<i-1){
p=p->next;
++j;
}//寻找第i个结点,并令p指向其前驱。
if(!(p->next)|| j>i-1) return ERROR;//删除位置不合理。
q=p->next;//临时保存被删除结点的地址以备释放。
p->next=q->next;//改变删除结点前驱结点的指针域。
e=p->data;//保存删除结点的指针域。
free(q);//释放删除结点的空间。
return OK;
}//ListDelete_L
(10):建立单链表:头插法——元素插入在链表头部。
实现代码:
void Create_H(LinkList &L,int n){
L=new Node; //L=(LinkList)malloc(sizeof(Node));
L->next=NULL;//先建立一个带头结点的单链表。
for(i=n;i>0;--i){
p=new Node;//生成新结点 p=(LinkList)malloc(sizeof(Node));
cin >>p->data;//输入元素值; scanf(&p->data);
p->next=L->next;//插入到表头
L->next=p; //将新结点插入头结点后面。
}
}//CreateList_H 时间复杂度O(n)
(10)-0:建立单链表:尾插法——元素插入在链表尾部。
实现算法:
//正位序输入n个元素的值,建立带头结点的单链表。
void CreateList_R(LinkList &L,int n){
L=new Node;
L->next=NULL;
r=L;//尾指针r指向头结点。
for(i=0;i<n;++i){
p=new Node;
cin << p->data;//生成新结点,输入元素值。
p->next=NULL;
r->next=p;//插入到表尾。
r=p;//r指向新的尾结点。
} //时间复杂度是:O(n)
}