1、基础知识
1.1 定义
线性表链式存储结构的特点是:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以不连续)。
根据线性表练市存储的特点可知,数据表示包括2部分:数据本身+指示其直接后继的信息;即节点=数据域+指针域。
n个节点链接成一个链表(又称线性链表或单链表),即为线性表(a1,a2,....,an)的链式存储结构。
1.2 单链表的逻辑状态
图1 单链表的逻辑状态
说明:(1)链表的存取必须从头指针开始进行。头指针指向链表中的第一个节点(首元节点)
(2)最后一个数据元素无后继,故指针为null。
2 单链表的基本操作
2.1 初始化
初始化即构造一个如上图1所示的空表。包含步骤如下:
(1)生成新节点的头结点,用头指针L指向头结点
(2)头节点的指针域为null
Status InitList(LinkList &L){ L =new LNode; L->next=null; return ok; }
2.2 取值
Status getElem(LinkList &L, int i, ElemType &e){ //在带头节点的单链表L中根据序号i获取元素的值,用e返回L中第i个数据元素的值 //初始化 p=L->next; j=1; while(p && j<1){ p=p->next; j++; } if(!p || j>i) return error; e=p->data; return ok; }
2.3 查找
LNode *LocalElem(LinkList L, ElemType e){ //在带头结点的单链表L中查找值为e的元素 p=L->next; while(p && p->data !=e) p=p->next; return p; }
2.4 新增
///将值为e的节点插入到单链表中 ///具体步骤:(1)找到链表中第i个位置的元素;(2)修改ai的后继,以及ai+1的前驱 Status ListInsert(LinkList &L, int i, ElemType e){ p=L;//头结点 j=0; while(p && (j<i-1)){ p=p->next; ++j; } if(!p || j>i-1) return errot; s =new LNode; s->data=e; s->next=p->next; p->next =s; return ok; }
2.5 删除
Status ListInsert(LinkList &L, int i){ p=L;//头结点 j=0; while(p && (j<i-1)){ p=p->next; ++j; } if(!(p->next) || (j>i-1)) return error; q=p->next; p->next=q->next; delete q; return ok; }
2.6 创建单链表
由于链表是一种动态结构,所占用的空间不需要预先分配划定,由系统自动生成,因此,线性表的链式存储结构的建立是一个动态过程。即从空表的初始状态起,依次建立各元素节点,并逐个插入列表。
(1)前插法
- 创建一个只有头结点的空链表
- 根据待创建链表包括的元素个数n, 循环n次执行以下操作:
-
- 生成一个新节点*p;
- 输入元素值赋给新节点*p的数据域;
- 将新节点*p插入到头结点之后
void CreateList_H(LinkList &L, int n){ L=new LNode; L->next =null; for(int i=0;i<n;i++){ p=new LNode; cin>>p->data; p->next = L->next; L->next =p; } }
(2) 后插法
算法步骤:
- 创建一个只有头结点的空链表
- 尾指针r初始化,指向头结点;
- 根据待创建链表包括的元素个数n, 循环n次执行以下操作:
-
- 生成一个新节点*p;
- 输入元素值赋给新节点*p的数据域;
- 将新节点*p插入到尾结点*r之后
- 尾指针r指向新的尾节点*p.
除单向链表外,还有循环链表,其特点为最后一个节点指针指向头结点。而对其操作与单链表基本一致。差别为判别条件的不同,需要将p!=null 或 p->next!=null 改为 p!=L 或 p->next !=L.
3. 双向链表