目录
1、循环链表
1.1 定义
是一种头尾相连的链表(即:表的最后一个结点的指针域指向 头结点,整个链表形成一个环)
1.2 优点
从表中的任何一个结点出发均可以找到表中的其他结点
1.3 链表的终止条件
判断他们是否指向了头指针
p != L p -> next != L
1.4 初始化链表
//初始化一个循环单链表
bool InitList(LinkList &L){
L=(LNode *)malloc(sizeof(LNode));//分配一个头结点
if(L==NUll) //内存分配不足,分配失败
return false;
L->next=L; //头结点next指向头结点
return true;
}
1.5 带有尾指针的循环链表
1.6 合并带有尾指针的两个循环链表
1.7 算法描述
LinkList Connect(LinkList Ta,LinkList Tb){
p = Ta->next; //p存表头结点
Ts->next = Tb->next->next; //Tb表头连接到Ta表尾
delete Tb->next; //释放Tb表头结点
Tb ->next=p; //修改指针
return Tb;
}
2、双向链表
2.1 定义
在单链表中,查找直接后继结点的执行时间为O(1),而查找直接前驱的执行时间为O(n)。为克服单链表这种单向性的缺点,可利用双向链表(Double Linked List)。
顾名思义,在双向链表的结点中有两个指针域,一个指向直接后继,另一个指向直接前驱。结点结构如下图所示。
双向循环链表
2.2 双向链表的初始化
typedef struct DuLNode{
ElemType data; //数据域
struct DuLNode *prior; //指向直接前驱
struct DuLNode *next; //指向直接后驱
}DuLNode,*DuLinkList;
2.3 双向链表的插入
bool ListInsert_DuL(DuLinkList &L,int i,ElemType e){
//在带头结点的双链表L中第i个位置之前插入元素e
DuLNode *p,*s;
if(!(p=GetElem_DuL(L,i))) //在L中确定第i个元素的位置指针p
return false; //p为NULL时,第i个元素不存在
s=(DuLNode *)malloc(sizeof(DuLNode));//生成新结点*s
s->data=e; //将结点*s数据域置为e
s->prior=p->prior; //将结点*s插入L中,此步对应上图①
p->prior->next=s; //对应上图②
s->next=p; //对应上图③
p->prior=s; //对应上图④
return true;
}
2.4 双链表的删除
void ListDelete_DuL(DuLinkList &L,int i){
//删除带头结点的双向链表L中的第i个元素
DuLNode *p,*s;
if(!(p=GetElem_DuL(L,i))) //在L中确定第i个元素的位置指针p
return false; //p为NULL时,第i个元素不存在
p->prior->next=p->next; //修改被删结点的前驱结点的后继指针,对应上图①
p->next->prior=p->prior; //修改被删结点的后继结点的前驱指针,对应上图②
free(p); //释放被删结点的空间
}
3、单链表、循环链表、双向链表的时间效率比较
4、顺序表和链表的比较
1)链式存储结构的优点:
-
结点空间可以动态申请和释放
-
数据元素的逻辑次序靠结点的指针来指示,插入和删除时不需要移动数据元素
2)链式存储结构的缺点:
-
存储密度小,每个结点的指针域需要额外占用存储空间,当每个结点的数据域所占的字节不多时,指针域所占用存储空间的比重显得很大
-
链式存储是非随机存取结构,对任一结点的操作都要从头结点依指针链查找到该结点,这增加了算法的复杂度
3)存储密度的大小
一般地,存储密度越大,存储空间的利用率就越高。显然,顺序表的存储密度为1,而链表的存储密度小于1
4)顺序表和链表的比较
5、线性表的合并
5.1 问题描述
假设利用两个线性表La和Lb分别表示两个集合A和B,现要求一个新的集合是二者的并集
5.2 代码呈现
void union(List &La,List Lb){
La_len = ListLength(La);
Lb_len = ListLength(Lb);
for(i=1;i<=Lb_Len;i++){
GetElem(Lb,i,e);
if(!LocateELem(La,e)) ListInSert(&La,++La_Len,e)
}
}
时间复杂度:O(ListLength(La)*ListLength(Lb),e);
6、有序表的合并
6.1 问题描述
已知线性表La和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的元素仍按值非递减有序排列
6.2 算法步骤
1)创建一个空表
2)依次从La或Lb中"摘取"元素值较小的结点插入到Lc表的最后,直至其中一个表变空为止
3)继续将La或Lb其中一个表的剩余结点插入到Lc表的最后
6.3 代码呈现
1)用顺序表实现
void MergeList_Sq(SqList,SqList.SqList &LC){
pa = LA.elem;
pb = LB.elem; //指针pa和pb的初值分别指向两个表的第一个元素
LC.length = LA.lenth+LB.length; //新表长度为待合并两表的长度之和
LC.elem = new ElemType[LC.length]; //为合并后的新表分配一个数组空间
pc=LC.elem; //指针pc指向新表的第一个元素
pa_last = LA.elem+LA.length-1; //指针pa_last指向LA表的最后一个元素
pa_last = LB.elem+LB.length-1; //指针pa_last指向LA表的最后一个元素
while(pa<=pa_Last&&pb<=pb_last){ //两个表都非空
if(*pa<=*pb) *pc++=*pa++; //依次"摘取"两表中值最小的结点
else *pc++=*pb++;
}
while(pa<=pa_last) *pc++=*pa++; //LB已到达表尾,将LA中剩下的元素加入LC
while(pa<=pa_last) *pc++=*pb++; //LA已到达表尾,将LB中剩下的元素加入LC
}//MergeList_Sq
空间复杂度:O(ListLength(La)+ListLEngth(Lb))
时间复杂度:O(ListLength(La)+ListLEngth(Lb))