第二章 线性表
线性结构
特点:只有一个首结点和尾结点
除首尾结点外其他结点只有一个直接前驱和一个直接后继
一对一
定义
具有相同特性的数据元素所组成的有限序列
存储
顺序存储-顺序表
特点:逻辑上相邻,物理上也相邻,随机存取
结构体定义
typedef int ElemType;
typedef struct {
ElemType *elem; //数据元素基地址
int length; //线性表当前长度
}SqList;
重要的运算
插入(倒着插)
思想:例如在第i个元素之前插入一个元素,需要将第i个及其至之后的元素后移,将元素插入到第i-1个元素的位置,顺序表长度+1
算法(这里只写算法,不是可以运行成功)
void Insert(SqList &L,int i,ElemType x){
for(int j=L.length-1;j>=i-1;j--){
L.elem[j+1]=L.elem[j];
L.elem[i-1]=x;
L.length++;
}
}
总结:先移后插,长+1,平均移动次数n/2
删除(正着删)
思想:删除第i个元素,第一次将第i+1个元素取代第i个元素,依次将后一个元素取代前一个,顺序表长度-1
算法:
void Delete(SqList &L,int i,ElemType &x){
x=L.elem[i];
for(int j=i;j<=L.length-1;j++){
L.elem[j]=L.elem[j+1];
L.length--;
}
}
总结:赋值前移长减一,平均移动次数(n-1)/2
链式存储-单链表
存储特点:逻辑上相邻,物理上不一定相邻,顺序存取
结构体定义:
typedef int ElemType;
typedef struct LNode{
ElemType data; //数据域
struct LNode *next; //指针域
}*LinkList;
重要的操作
插入
例如,将s指向的结点插入到p指向的结点之后
思想:s->next=p->next;p->next=s;
先将x结点和链表中b结点连接,在将a结点与x结点连接
需要注意的是插入过程中不要将链断开,这也就是先连后再连前的原因了
删除
例如将p指向结点的下一个结点删除
思想:p->next=p->next->next;
删除的话比较好理解,直接将a结点和b的后继结点相连,这样就成功的删除了b结点
建立单链表
头插法(带头结点)
思想:
生成新结点
将要插入的数据存到新结点的数据域中
将新结点插入到链表的前端
算法:
void CreateList(LinkList &L,int n){
LinkList p;
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;
}
}
尾插法
思想:
新增一个尾指针r指向尾结点,
初始时尾指针和头指针同时指向头结点
**新生成一个结点,将输入的数据存入数据域,新结点插入到尾结点之后,尾指针实时指向尾结点。**循环操作
算法:
void CreateList(LinkList &L,int n){
LinkList p,r;
L =new LNode;
L->next=null; //生成带头结点的单链表
r=L; //头尾指针指向头结点
for(int i=0;i<n;i++){
p = new LNode; //生成新结点
cin>>p->data; //输入要插入的元素值
r->next=p; //新结点插入到表尾
r=p; //尾指针指向新的尾结点
}
}
循环链表
定义:尾结点的指针域不再是空,而是指向链表头结点,整个链表形成一个环。(这里不作重点说明,重点掌握单链表)
特点:从任意结点出发都能访问到其他的结点。
双向链表
前面我们说到单链表,它的插入删除操作的时间复杂度都是O(1),但它访问某元素时的时间复杂度就是O(n),如果已知了一个元素,要删除它后面的元素,简单一步就做到了,时间复杂度就是O(1),但如果要删除它前面元素呢,就比较复杂了,此时指针已经指向这个元素,它是单向的,只能从前往后,由此引出双向链表。
定义:每个结点有两个指针域,分别指向它的前驱和后继结点
结构体定义:
typedef int ElemType;
typedef struct LNode{
ElemType data; //数据域
struct LNode *prior; //指向前驱结点
struct LNode *next; //指向后继结点
}*LinkList;
重要的操作
插入
前面我们说了单链表的插入和删除,这里呢,差不多意思。
例如:将x插入到a,b之间
思想:正向插完,反向插,中间链不能断开。
s->next=p;
p->prior->next=s;
s->prior=p->prior;
p->prior=s;
另一种方法:左边连好,连右边,中间链不能断开
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;
删除
例:删除p所指的结点
思想:正向删完,反向删
p->prior->next=p->next;
p->next->prior=p->prior;