引言:
我们都知道,盖房子需要坚实的基础,作为一个学完数据结构的弱鸡,我真切的感到了基础的力量。排开那些基本的概念,那些算法计算的表达。我们之后的大部分操作,都是建立在线性表的基础上,所以我们要学会利用这两大工具——顺序表和链表。只有掌握了它们,之后所有的算法才可以去谈实现,不然都是纸上谈兵(当然啦,会算法也很重要)。那么我们一起来学习吧,所有的讲解都是按照:初始化、取值、查找、插入、删除(创建---这里链表才有)这个线性方式。这里可以给出一个目录,方便大家进行阅读。
目录
一、顺序表
1.初始化
【算法步骤】
- 为顺序表L动态分配一个预定义大小的数组空间,使elem指向这段空间的基地址。
- 将表的当前长度设为0。
【算法描述】
void InitList(SqList &L)
{//构造一个空的顺序表L
L.elem = new ElemType[MAXSIZE];//为顺序表分配一个大小为MAXSIZE的数组空间
if(!L.elem) exit(OVERFLOW);//存储分配失败退出
L.length = 0;//空表长度为0
}
2.取值
【算法步骤】
- 判断指定的位置序号i值是否合理(1<=i<=L.length),若不合理,则返回ERROE。
- 若i值合理,则将第i个数据元素L.elem[i-1]赋给参数e,通过e返回第i个数据元素的传值。
【算法描述】
int GetElem(SqList L,int i,ElemType &e)
{
if(i<1||i>L.length) return ERROR;//判断i值是否合理,若不合理,返回ERROR
e = L.elem[i-1];//elem[i-1];//elem[i-1]单元存储第i个数据元素
return e;
}
3.查找
【算法步骤】
- 从第一个元素起,依次和e相比较,若找到与e相等的元素L.elem[i],若查找成功,返回该元素的序号i+1。
- 若查遍整个顺序表都没有找到,则查找失败,返回0。
【算法描述】
int LocateElem(SqList L,ElemType e)
{//在顺序表L中查找值为e的数据元素,返回其序号
for(i=0;i<;.length;i++)
if(L.elem[i]==e) return i+1;//查找成功,返回序号i+1
return 0;//查找失败
}
4.插入
【算法步骤】
- 判断插入位置i是否合法(i值的合法范围是1<=i<=n+1),若不合法则返回ERROR
- 判断顺序表的存储空间是否已满,若满则返回ERROR
- 将第n个至第i个位置的元素依次向后移动一个位置,空出第i个位置(i=n+1时无需移动)
- 将要插入的新元素e放入第i个位置
- 表长加1
【算法描述】
void ListInsert(Sqlist &L,int i,ElemType e)
{//在顺序表L中第i个位置插入新的元素e,i值的合法范围是1<=i<=L.length+1
if((i<1)||(i>L.length+1) return ERROR;//i值不合法
if(L.length==MAXSIZE) return ERROR;//当前储存空间已满
for(j=L.length-1;j>=i-1;j--)
L.elem[j+1]=L.elem[j];//插入位置及之后的元素后移
L.elem[i-1]=e;//将新元素e放入第i个位置
++L.length;//表长加1
}
5.删除
【算法步骤】
- 判断删除位置i是否合法(合法值为1<=i<=n),若不合法则返回ERROR。
- 将第i+1个至第n个元素依次向前移动一个位置(i=n时无需移动)
- 表长减1
【算法描述】
void ListDelete(SqList &L,int i)
{//在顺序表L中删除第i个元素,i值的合法范围是1<=i<=L.length
if((i<1)||(i>L.length)) return ERROR; //i值不合法
for (j=i; j<=L.length-1; j++)
L.elem[j-1]=L.elem[j]; //被删除元素之后的元素前移
--L.length; //表长减1
}
二、单链表
1.初始化
【算法步骤】
- 申请头结点,用头指针L指向头结点。
- 头结点的指针域置空。
【算法描述】
void InitList(LinkList &L)
{//构造一个空的单链表L
L=new LNode;//生成新结点作为头结点,用头指针L指向头结点
L->next=NULL; //头结点的指针域置空
}
2.取值
【算法步骤】
- 用指针p指向首元结点,用j做计数器初值赋为1
- 从首元结点开始依次顺着链域next向下访问,只要指向当前结点的指针p不为空(NULL),并且没有到达序号为i的节点,则循环执行以下操作:
p指向下一个结点
计数器j相应加1
- 退出循环时,如果指针p为空,或者计数器j大于i,说明指定的序号i值不合法(i大于表长n或i小于等于0),取值失败返回ERROR;否则取值成功,此时j=i时,p所指的结点就是要找的第i个结点,用参数e保存当前结点的数据域,返回数值。
【算法描述】
int GetElem(LinkList L, int i, ElemType &e)
{//在带头结点的单链表L中根据序号i获取元素的值,用e返回L中第i个数据元素的值
p=L->next;j=1; //初始化
while(p&&j<i) //向后扫描,直到p指向第i个元素或p为空
{
p=p->next; ++j;
}
if(!p || j>i) return ERROR; //第i个元素不存在
e=p->data; //取第i个元素,e带回
return e;
}
3.查找
【算法步骤】
- 用指针p指向首元结点
- 从首元结点开始依次顺着链域next向下查找,只要指向当前节结点的指针p不为空,并且p所指结点的数据域不等于给定值e,则循环执行以下操作:p指向下一个节点
- 返回p。若查找成功,p此时即为结点的地址值,若查找失败,p的值即为NULL
【算法描述】
LNode *LocateELem_L (LinkList L,Elemtype e)
{ //在带头结点的单链表L中查找值为e的元素
p=L->next;//初始化,p指向首元结点
while(p &&p->data!=e) //顺链域向后扫描,直到p为空或p所指结点的数据域等于e
p=p->next; //p指向下一个结点
return p; //查找成功返回值为e的结点地址p,查找失败p为NULL
}
4.插入
【算法步骤】
- 查找结点a(i-1)并由指针p指向该结点
- 生成一个新结点*s
- 将新结点*s的数据域置为e
- 将新结点*s的指针域指向结点ai
- 将结点*p的指针域指向新结点*s
【算法描述】
void ListInsert(LinkList &L,int i,ElemType e){
p=L;j=0;
while(p&&j<i−1)
{p=p->next;++j;} //寻找第i−1个结点
if(!p||j>i−1) return ERROR; //插入位置不合理
s=new LNode; //生成新结点s
s->data=e; //将结点s的数据域置为e
s->next=p->next; //将结点s插入L中
p->next=s;
}
5.删除
【算法步骤】
- 查找结点a(i-1)并由指针p指向该结点
- 临时保存待删除结点ai的地址在q中,以备释放
- 将结点*p的指针域指向ai的直接后继结点
- 释放结点ai的空间
【算法描述】
void ListDelete(LinkList &L,int i,ElemType &e)
{//在带头结点的单链表L中,删除第i个元素
p=L; j=0;
while( p->next &&j<i-1) //寻找第i-1个结点
{ p=p->next; ++j; }
if(!(p->next)||j>i-1) return ERROR; //删除位置不合理
q=p->next; //临时保存被删结点的地址,以备释放空间
p->next=q->next; //修改前驱结点的指针域
delete q; //释放删除结点的空间
}
6.创建
①前插法创建单链表
【算法步骤】
- 创建一个只有头结点的空链表
- 根据待创建链表的元素个数n,循环n次以下操作: 生成一个新结点, 由p指向; 给新结点的数据域输入元素值; 将新结点插入到头结点之后.
【算法描述】
void CreateList_F(LinkList &L,int n)
{//逆位序输入n个元素的值,建立带表头结点的单链表L
L=new LNode;
L->next=NULL; //建立一个带头结点的单链表
for(i=0;i<n;++i)
{
p=new LNode; //生成新结点
cin>>p->data; //输入元素值
p->next=L->next;
L->next=p; //插入到表头
}
}
②后插法创建单链表
【算法步骤】
- 创建一个只有头结点的空链表
- 将辅助尾指针 r 初始化,使其指向头结点
- 根据待创建链表包括的元素个数n,循环以下操作: 生成一个新结点,由p指向; 给新结点的数据域输入元素值; 将新结点插入到尾结点r之后 尾指针r改为指向新的尾结点
【算法描述】
void CreateList_L(LinkList &L,int n)
{ //正位序输入n个元素的值,建立带表头结点的单链表L
L=new LNode;
L->next=NULL;//先建立一个带头结点的空链表
r=L; //尾指针r初始指向头结点
for(i=0;i<n;++i)
{
p=new LNode; //生成新结点
cin>>p->data; //输入元素值
p->next=NULL; r->next=p; //插入到表尾
r=p; //让r指向新的尾结点
}
}
三、循环链表和双向链表简单介绍
【循环链表】
单链表循环条件: 单向循环链表循环条件:
p!=NULL p!=L (不带头结点)
p->next!=NULL p->next!=L (带头结点)
【双向链表】
结构体:
typedef struct DuLNode{
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode, *DLinkList
相关操作:
①插入
Status ListInsert_DuL(DuLinkList&L,int i,ElemType e)
{ if( ! (p=GetElemP_DuL(L,i) ) ) return ERROR;
s=new DuLNode;
s->data=e;
s->prior=p->prior;
p->prior->next=s;
s->next=p;
p->prior=s;
return OK;
}
②删除
Status ListDelete_DuL(DuLinkList &L,int i)
{
if(!(p=GetElemP_DuL(L,i))) return ERROR;
p->prior->next=p->next;
p->next->prior=p->prior;
delete p;
return OK;
}
后记:
如果有误评论指出,谢谢,建议写一个图书管理系统或者多项式相加来熟悉相关的操作。