线性表的类型定义
一个线性表是n个数据元素的有限序列
同一个线性表中的元素属于同一数据对象
线性表的顺序表示和实现
线性表的顺序表示是用一组地址连续的存储单元依次存储线性表的数据元素
顺序表是一种随机存取的存储结构(随机存取:查找所需时间与元素所在位置无关),也就是说在顺序表中查找元素(已知元素位置)的时间复杂度为O(1)
但在顺序表中插入和删除元素,时间复杂度均为O(n)
#define LIST_INIT_SIZE 100 //初始分配量
#define LISTINCREMENT 10 //分配增量
typedef struct {
ElemType elem[LISTSIZE];
int length; //当前长度
int listsize; //当前分配的存储容量
} SqList; // 俗称 顺序表
Status ListInsert_Sq(SqList &L, int i, ElemType e) {
// 在顺序表L的第 i 个元素之前插入新的元素e,
// i 的合法范围为 1≤i≤L.length+1
q = &(L.elem[i-1]); // q 指示插入位置
for (p = &(L.elem[L.length-1]); p >= q; --p)
*(p+1) = *p; // 插入位置及之后的元素右移
*q = e; // 插入e
++L.length; // 表长增1
return OK;
} // ListInsert_Sq
Status ListDelete_Sq(SqList &L, int i, ElemType &e) {
if ((i < 1) || (i > L.length)) return ERROR; // 删除位置不合法
p = &(L.elem[i-1]); // p 为被删除元素的位置
e = *p; // 被删除元素的值赋给 e
q = L.elem+L.length-1; // 表尾元素的位置
for (++p; p <= q; ++p)
*(p-1) = *p; // 被删除元素之后的元素左移
--L.length; // 表长减1
return OK;
} // ListDelete_Sq
线性表的链式表示和实现
线性表的链式存储结构是用一组任意的存储单元(不需要一定连续)存储线性表的数据元素,因此为了找到每个数据元素a与其后继元素之间的逻辑关系,对数据元素a来说,不仅要存储本身的信息,还要存储一个其直接后继的存储位置。
用头指针指向单链表的第一个数据元素的存储位置
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
在单链表中,每一个数据元素的位置只能从头指针出发寻找,而不能通过起始位置计算得出,因此单链表是顺序存取的存储结构
Status GetElem_L(LinkList L,int i,ElemType &e){
p = L->next;//p指向的单链表的第一个结点
j = 1; //计数器
while(p&&j<i){
p = p->next;
++j;
}
if(p==NULL || j>i) return Error;
e = p->data;
return OK;
}
插入和删除
插入
在单链表中插入节点只需要修改指针,如果在第i个结点之前插入元素,就修改第i-1个结点的指针
Status ListInsert_L(LinkList &L, int i, ElemType e) {
// L 为带头结点的单链表的头指针,本算法
// 在链表中第i 个结点之前插入新的元素 e
p = L;
j = 0;
while (p && j < i-1)
{
p = p->next;
++j;
} // 寻找第 i-1 个结点
if (!p || j > i-1)
return ERROR; // i 大于表长或者小于1
s = new LNode; // 生成新结点
if ( s == NULL) return ERROR;
s->data = e;
s->next = p->next;
p->next = s; // 插入
return OK;
} // LinstInsert_L
删除
Status ListDelete_L(LinkList &L, int i, ElemType &e) {
// 删除以 L 为头指针(带头结点)的单链表中第 i 个结点
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 = q->data;
delete(q);
return OK;
} // ListDelete_L
单链表的建立
头插法
每一个新来的结点都放在开头,最后所得的单链表结点次序与输入的相反
//带头结点的头插法
void CreateList_L(LinkList &L,int n){
L = new LNode;
L -> next = NULL;
for(i = n;i>0;--i){
p = new LNode;
scanf(&p->data);
p->next = L->next;
L->next = p;
}
}
尾插法
linklist creatLinkList_L(){
char ch;
LinkList head;
LNode *p,*r; //(, *head;)
head=NULL; //头指针
r=NULL;//尾指针
while ((ch=getchar( )!=‵\n′){
p=new LNode;
p–>data=ch;
if (head=NULL)
head=p;//在头指针为空的时候添加结点,为第一个节点,令头指针指向第一个节点,这是有头结点和无头结点操作的差别
else
r–>next=p;
r=p; //令尾指针指向最后一个位置
}
if (r!=NULL) //如果链表非空,应将最后一个结点的指针域置为空
r–>next=NULL;
return(head);
}
其他形式的链表
循环链表
最后一个结点的指针指向第一个结点
算法中的循环条件不再是是否为空,而是是否等于头指针。同时为了更方便的查找,也会使用尾指针(rear)来表示单循环链表
//例、在设尾指针的单循环链表上实现将两个线性表(a1,a2,a3,…an)和(b1,b2,b3,…bn)链接成一个线性表的运算。
linklist connect(linklist A,linklist B)
{
LinkList p=A—>next;//A B为尾指针
A—>next=(B—>next)—>next ;
free(B—>next);
B—>next=p;
A=B;
return(A);
}
双向链表&&双循环链表
typedef struct DuLNode {
ElemType data; // 数据域
struct DuLNode *prior; // 指向前驱的指针域
struct DuLNode *next; // 指向后继的指针域
} DuLNode, *DuLinkList;
//插入
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){
//在带头结点的双循环链表的第i个位置前插入元素e
if(!(p = GetElemP_DuL(L,i)))
return ERROR;//确定第i个元素的位置
if(!(s = new DuLNode)) return ERROR;
s->data = e;
s->prior = p->prior;
p->prior->next = s;
s ->next = p;
p->prior = s;
}
//删除带头结点的双循环链表第i个元素
Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e){
if(!(p = GetElemP_DuL(L,i)))
return Error;
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
}