您的位置:首页 > 理论基础 > 数据结构算法

线性表之顺序表

2016-09-29 15:33 183 查看
数据结构分为线性结构和非线性结构,线性结构是简单常用的数据结构,线性表是典型的线性结构。

线性表的定义是由N个(N>=0)节点或者表项构成,他是有限数列,邻接关系是1:1,有两种:有序和无序

线性表可以有不同的数据类型,如广义表,广义表表中元素自身具有某种结构,属于线性表,是线性表的推广

线性表有两种存储方式:顺序存储和链式存储,有基于数组的、基于链表的、散列的表示

顺序表是基于数组的顺序存储,可以那顺序一次访问或者随机访问,每个表项的存储空间相同

注意:表的起始元素是从1开始的,数组是从0开始的,第 m个表项对应的是数组m-1个

存储分为静态存储和动态存储,动态存储可以扩展存储空间提高灵活性 

在Search、Locate、getDatas这几个函数定义中是常函数const,因为const成员函数执行时不能调用非const成员函数,表明函数不能改变对象的函数值 

线性表的各个常用函数 表示

1.搜索函数,如果有值等于X,返回表型第几个元素

int SeqList<T>::search(T& x)const{
for(int i=0;i<=last;i++)
if(data[i] == x) return i+1;
return 0;
}


2.插入函数,将X插入到第 i (0 <= i <= last+1)个表项,可以插在第一个前面可以是最后一个后面,所以是从0开始到last+1结束

bool SeqList<T>::Insert(int i ,T& x){
if(last == maxSize-1) return false;	//表满,不能插入
if(i<0 || i>last+1) return false;	//i数据不合理,不能插入
for(int j = last;j>=i;j--)
data[j+1] = data[j];	//向后移动,空出i
data[i] = x;	//插入
last++;
return true;
}
这里采用的是从最后一位开始后移来实现,这个方向是不能变的,不能从前面开始,下面这是错误的例子,注意啊是错误的

bool SeqList<T>::Insert(int i ,T& x){
if(last == maxSize-1) return false;	//表满,不能插入
if(i<0 || i>last+1) return false;	//i数据不合理,不能插入
for(int j = i;j<last;j++)
data[j+1] = data[j];
data[i] = x;	//插入
last++;
return true;
}
这个和上面的区别在于移动的顺序不一样,这是从前向后移动,这样的话,我们来看一下,执行第一步data[ j ]的值赋给data[ j+1],j++之后,原本的data[ j+1]的值被覆盖掉了,不存在了,执行data[ j+2] = data[ j+1]时还是最开始的data[ j ]的值,后面的所有数据都被冲掉了,都变成data[ i ]的值了,所以这样是不对的,要从后开始

3.删除函数, 值等于X的删除

bool SeqList<T>::Remove(int i ,T& x){
if(last == -1) return false;	//表空,不能删除
if(i<1 || i>last+1) return false;	//i数据不合理,不能删除
for(int j = i;j<=last;j++)
data[j-1] = data[j];	//向前移
last--;
return true;
}

这个是从前面开始,顺序依然不能变,如果从后面向前推的话,数据被冲掉,都是data[last]

3.2删除值为X的所有元素

void deleteValue(SeqList& L,DataType x){
int i,k=0;	//记录不等于X的指针位置
for(i=0;i<L.n;i++){
if(L.data[i] != x){
if(i != k){
/*把不等于的直接移到前面指针记录的位置
因为k=0,k<=i,所以不会出现冲掉数
遍历过的数中,不等于X向前代替,等于X的位置都被不等于的占了
最后长度是只有不等于X的长度,等于的就被删了
*/
L.data[k]=L.data[i];
}
k++;	//i=k,说明前面没有等于X的,都在原来的位置上
}
}
L.n = k;	//只留下不等于X的,所以表的长度就是K的位置
}


3.3删除表中重复元素

int deleteSame(SeqList& L){
int i,k=1;
if(L.n == 0) return 0;
for(i=1;i<L.n;i++){	//从第二个数开始比起,和前一项比
if(L.data[i-1] != L.data[i])
if(k!=i) L.data[k]=L.data[i];
k++;
}
L.n=k;
return 1;
}


注意在插入和删除前要判断表是否是空表或者满表,数据 i 是否合理

顺序表搜索算法的时间代价是数据比较次数衡量,插入和删除是循环内数据移动次数决定的

搜索算法最坏情况是比较n+1次(最后一次检测 i > last,没有数据比较),平均次数是n+1/2

插入时平均数据移动次数是n/2,删除时是n-1/2次

顺序表查找时间复杂度是O(1),插入和删除的复杂度是O(n),进行插入和删除的时间代价相对较高 

顺序表的应用

可以把两个顺序表看作是集合,实现”交并“

void union(SeqList<int>& LA,SeqList<int>& LB){	//并集
int n = LA.Length(),m = LB.Length(),i,k,x;
for(i=1;i<=m;i++)
LB.getData(i,x);	//从B中取出元素
k = LA.Search(x);	//在A中查找有没有
if(k == 0) LA.Insert(n,x);n++;	//如果没有就将x插入到A中
}

void intersection(SeqList<int>& LA,SeqList<int>& LB){	//交集
int n = LA.Length(),m = LB.Length(),i=1,k,x;
while(i<=n){
LA.getData(i,x);	//从A中取出元素
k = LB.Search(x);	//在B中查找有没有
if(k == 0) LA.Remove(i,x);n--;	//如果没有就将x删除
}

}
在并集的时候采用的是从B中取元素,没有就添加到A中,而在交集的时候是在A中取元素,将B中没有的删除,之所以不在B取元素是因为添加可以在最后进行,删除不可以,删除必须在数据原本的位置上删除,这就需要remove时获取 i 的位置,只能循环遍历A然后在A中删除
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息