问题:如何判断某个数据元素是否存在于线性表中?
遗失的操作-find:
可以为线性表(List)增加一个查找操作
int find(const T& e)const
参数:待查找的数据元素
返回值:
>=0: 数据元素在线性表中第一次出现的位置。
-1:数据元素不存在。
int find(const T& e) const //o(n)
{
int ret=-1;int i=0;
Node* node=m_header.next;
while(node)
{
if(node->value==e)
{
ret=i;
break;
}
else
{
node=node->next;
i++;
}
}
return ret;
}
#include <iostream>
#include "LinkList.h"
using namespace WSlib;
using namespace std;
class Test:public Wobject //如果链表存储自定义类类型,那么自定义类型就要继承顶层父类,这样就能避免编译错误,通过编译
{
int i;
public:
Test(int v=0)
{
i=v;
}
bool operator ==(const Test& t) //重新实现重载==操作符
{
return (i==t.i);
}
};
int main()
{
Test t1(1);
Test t2(2);
Test t3(3);
LinkList<Test> lis;
//如果我们创建一个单链表对象,保存的数据元素是自定义类对象,没有实际的查找操作但是会出错,为了不让编译器出错,
//就必须重载==操作符,这样就更麻烦了,那find该存在吗,解决方法:两全方法,在顶层父类Wobject实现默认相等比较操作符实现,
//这个顶层父类中的相等操作符重载只是为了让编译器不报错,而查找的依据是自定义类中i的值,还需在子类中重新实现相等操作符的函数。
lis.insert(t1);
lis.insert(t2);
lis.insert(t3);
cout<<lis.find(t2)<<endl;
LinkList<int> list;
for(int i=0;i<5;i++)
{
list.insert(0,i);
}
for(int i=0;i<4;i++)
{
cout<<list.find(i)<<endl;
}
return 0;
}
/*
时间复杂度对比分析:顺序表,单链表
操作 SeqList LinkList
insert o(n) o(n)
remove o(n) o(n)
set o(1) o(n)
get o(1) o(n)
find o(n) o(n)
length o(1) o(1)
clear o(1) o(n)
*/
有趣的问题:顺序表的整体时间复杂度比单链表要低,那么单链表还有使用价值吗?
效率的深度分析:实际工程中,时间复杂度只是效率的一个参考指标:并不代表效率的全部
对于内置基础类型,顺序表和单链表的效率不相上下。顺序表高一点
对于自定义类类型,顺序表在效率上低于单链表。
插入和删除:
顺序表:设计大量数据对象的复制操作。
单链表:只涉及指针操作,效率与数据对象无关。
数据访问:
顺序表:随机访问,可直接定位数据对象。
单链表:顺序访问,必须从头访问数据对象,无法直接定位。
工程开发的选择:
顺序表:1数据元素的类型相对简单,不涉及深拷贝。2数据元素相对稳定,访问操作远多于插入和删除操作。
单链表:1数据元素的类型相对复杂,复制操作相对耗时。2数据元素不稳定,需要经常插入和删除,访问操作较少。
小结:线性表中元素的查找依赖于相等比较操作符(==),在顶层父类提供了默认相等和不相等操作符实现,如果需要自定义类类型,最好继承自顶层父类Wobject 。顺序表适用于访问需求量较大的场合(随机访问),单链表适用于数据元素频繁插入和删除的场合(顺序访问)。当数据类型相对简单时,顺序表和单链表的效率不相上下。