线性表,顾名思义,线性排列形成一个表状的结构.有两种存储结构,一为顺序存储模式,二为链表模式,各有所长,互相补足.
一、顺序存储结构
(1)特征及定义:用一段地址连续的存储单元依次存储线性表的数据元素,结构规整,多用数组来表示.
#define MAXSIZE 20 //存储空间初始分配量
typedef int ElemType;
typedef struct
{
ElemType data[MAXSIZE];//数据存储数据元素,最大值为MAXSIZE,这是在申请一块大小为20的地址连续的存储单元
int length;//线性表当前的长度<=MAXSIZE
}SqList;
(2)表的操作:
a.获取表中第i个位置元素算法思路:第i个元素即为表中数组下标为i-1的元素;其次,i的值必须在数组下标范围内。
b.顺序存储结构形式的线性表插入算法思路:如果插入位置不合理,抛出异常;如果线性表的长度>=数组长度,则抛出异常或者动态的增加容量;从最后一个元素开始向前遍历,到第i个位置,分别将它们都向后移动一个位置;将要插入元素填入位置i处;表长+1。
int ListInsert(Sqlist *L,int i,ElemType e)
{
int k;
if(L->length==MAXSIZE)//顺序线性表已满
return 0;
if(i<1||i>L->length+1)//i不在范围内
return 0;
if(i<=L->length)//若插入的数据位置不在表尾时
{
for(k=L->length-1;k>=i-1;k--)//将插入位置之后的数据元素向后移动一位
L->data[k+1]=L->data[k];
}
L->data[i-1]=e;//插入新元素
L->length++;
return 1;
}
c.删除算法的思路:如果删除位置不合理,抛出异常;取出删除元素;从删除元素位置开始遍历到最后一个元素位置,分别将它们都向前移动一个位置;表长-1。
int ListDelete(SqList * L,int i,ElemType *e)
{
int k;
if(L->length==0)
return 0;
if(i<1||i>L->length)
return 0;
*e=L->data[i-1];
if(ilength)
{
for(k=i;klength;k++)
L->data[k-1]=L->data[k];
}
L->length--;
return 1;
}
(3)优点:快速存取表中任意位置的元素,插入和删除操作需要移动大量元素,存储空间易产生碎片。
二、链表存储结构
(1) 特征及定义:存储单元不一定连续,结构多用指针。
typedef struct Node
{
ElemType data;
struct Node *next;
}Node;
typedef struct Node *LinkList;
假如说p是指向第i个元素的指针,那么这个元素就是p-〉data,而p-〉next-〉d
ata就是第i+1的元素。
(2)获取链表中第i个数据的算法思路:声明一个指针p指向链表的第一个节点,遍历链表,p不断后移,计数递增,遇到链表末尾指针为空,则说明第i个节点不存在,否则,查找成功,返回节点p的数据。
int GetElem(LinkList L,int i,ElemType *e)
{
int j;
LinkList p;
p=L->next;
j=1;
while(p&&jnext;
++j;
}
if(!p||j>i)
return 0;
*e=p->data;
return 1;
}
(3)插入思想
:比如说面试过程中,一个迟到的人赶来排到相应的位置,按照名单他是第i个上场的,那么第i-1个人面试完后,面试官让他叫下一个人进来,那么他就需要知道下一个人在那,如此插进来的人还要知道第i+1个人在哪,这样就完成了插入过程。
算法思路:首先查找第i个数据的位置,如(2)所述,查找成功后,建立一个空节点s,将需要插入的新元素赋值给s->data,然后进行插入思想中标准动作,指针转移:s->next=p->next,p->next=s这个地址转移顺序不能错,为什么呢,反过来转移,p->next已经被s给覆盖了,那s->next找谁去评理
int ListInsert(ListList *L,int i,ElemType e)
{
int j;
ListList p,s;
p=*L;
j=1;
while(p&&jnext;
++j;
}
if(!p||j>i)
return 0;
s=(ListList)malloc(sizeof(Node));
s->data=e;
s->next=p->next;
p->next=s;
return 1;
}
(4)删除思想:欲删除第i个节点,意思就是让第i-1个节点的指针p绕过第i个直接指向第i+1个节点,即p->next=p->next->next;
删除算法:重复获取过程,查找成功后按照删除思想操作,稍作改动另设指针q=p->next;p->next=q->next,将q指针所占的空间释放掉,利用free。
int ListDelete(ListList *L,int i,ElemType *e)
{
int j;
ListList p,q;
p=*L;
j=1;
while(p&&jnext;
++j;
}
if(!p||j>i)
return 0;
q=p->next;
p->next=q->next;
*e=q->data;
free(q);
return 1;
}
(5)创建一个空的单链表:创建空链表相当于设置一个动态的产生节点,来一个,创建一个。有两种方法,头插法和尾插法,一个始终让新节点在第一的位置,一个是始终在最后。
创建算法:声明一个指针p和计数器变量i;初始化空链表L;让L的头结点的指针指向NULL;循环生成新节点插入过程。相比而言,尾插法更好理解,头插法声明了一个指针的指针**
//头插法
void CreatListHead(ListList *L,int n)
{
ListList p;
int i;
srand(time(0));
*L=(ListList)malloc(sizeof(Node));
(*L)->next=NULL;
for(i=0;idata=rand()%100+1;
p->next=(*L)->next;
(*L)->next=p;
}
}
//尾插法
void CreatListHead(ListList *L,int n)
{
ListList p,r;
int i;
srand(time(0));
*L=(ListList)malloc(sizeof(Node));
r=*L;
for(i=0;i {
p=(ListList)malloc(sizeof(Node));
p->data=rand()%100+1;
r->next=p;
r=p;
}
r->next=NULL;
}
int ClearList(ListList *L)
{
ListList p,q;
p=(*L)->next;
while(p)
{
q=p->next;
free(p);
p=q;
}
(*L)->next=NULL;
return 1;
}