昨晚数据结构最简单也是最基础的线性表,有两种实现方式:
1、是逻辑结构与物理结构一致的顺序表,具体来说,就是用数组来实现
2、是数据的逻辑次序与物理次序很有可能不一致的链式表,通过结点来存储后继点的指针地址
顺序表定义:
const int MAX=100;
template<typename T>
class seqlist{
private:
T data[MAX];
int size;
public:
seqlist(){size=0;}
seqlist(T a[],int n){
if(n>MAX)throw "n error";
for(int i=0;i<n;i++)
data[i]=a[i];
size=n;}
~seqlist(){}
int getsize(){return size;}
T get(int i);
int loc(T x);
void insert(int i,T x);
T dele(int i);
void prt();};
template<typename T>
T seqlist<T>::get(int i){
if(i>size||i<1)throw"i error";
return data[i-1];}
template<typename T>
int seqlist<T>::loc(T x){
for(int i=0;i<size;i++)
if(data[i]==x) return i+1;
return -1;}
template<typename T>
void seqlist<T>::insert(int i,T x){
if(size>=MAX)throw"overflow";
if(i>size+1||i<1)throw"i error";
for(int j=size;j>=i;j--)
data[j]=data[j-1];
data[i-1]=x;
size++;}
template<typename T>
T seqlist<T>::dele(int i){
if(size<1)throw"downflow";
if(i<1||i>size)throw"i error";
T x=data[i-1];
for(int j=i;j<size;j++)
data[j-1]=data[j];
size--;
return x;
}
template<typename T>
void seqlist<T>::prt(){
if(size<1)cout<<"empty"<<endl;
else {
for(int i=0;i<size;i++)
cout<<data[i]<<" ";
cout<<endl;}}
链式表(以结点只含一个指针的单链表为例):
//link list
template<typename T>
struct node{
T data;
node<T>*next;};
template<typename T>
class linklist{
private:node<T>*first;//单链表的头指针
int linksize;
public:
linklist(){fisrt=new node<T>;
first->next=NULL;//无参构造构造空线性表
linksize=0;}
linklist(T a[],int n){
first=new node<T>;
first->next=NULL;//先构造空链表
linksize=n;
node<T>*p=first;
for(int i=0;i<n;i++)
{node<T>*s=new node<T>;
s->data=a[i];
s->next=p->next;//插入到头节点之后
p->next=s;}}
~linklist(){
node<T>*p=first;
while(p){
node<T>*q=p;
p=p->next;
delete q;}}
int size();
T get(int i);
int loc(T x);
void insert(int i,T x);
T del(int i);
void prt();};
template<typename T>
int linklist<T>::size(){
return linksize;}
template<typename T>
T linklist<T>::get(int i){
node<T>*p=first;
int j=0;
while(p&&j<i){
p=p->next;
j++;}
if(!p) throw"i error";
else return p->data;}
template<typename T>
int linklist<T>::loc(T x){
node<T>*p=first;
int j=0;
while(p&&x!=p->data){
p=p->next;
j++;}
if(!p)throw"x no";
else return j;}
template<typename T>
void linklist<T>::insert(int i,T x){
node<T>*p=first;
int j=0;
while(p&&j<i-1){
p=p->next;
j++;}//找到i-1
if(!p)throw"insert error";
else{
node<T>*s=new node<T>;
s->data=x;
s->next=p->next;
p->next=s;}
linksize++;}
template<typename T>
T linklist<T>::del(int i){
node<T>*p=first;
int j=0;
while(p&&j<i-1){
p=p->next;
j++;}
if(!p||!p->next)throw"del error";
else{
T t=p->next->data;
p->next=p->next->next;
return t;}
linksize--;}
template<typename T>
void linklist<T>::prt(){
node<T>*p=first;
if(!p)cout<<"empty"<<endl;
p=p->next;
while(p){
cout<<p->data<<" ";
p=p->next;}
cout<<endl;}
两者的调用类似,因为只是内部实现不一样,其接口还是不变。这体现了数据结构的封装性:
#include"2.h"
int main(){
int a[]={10,12,15,25,8,16,20};
seqlist<int>li(a,7);
linklist<int>l(a,7);
cout<<"the inf li:"<<endl;
li.prt();
cout<<"the inf of linklist:"<<endl;
l.prt();
try{
cout<<"the size of seqlist:"<<endl;
cout<<li.getsize()<<endl;
cout<<"the size of linksize:"<<endl;
cout<<l.size()<<endl;
cout<<"find the ith:"<<endl;
cout<<li.get(3)<<endl;
cout<<"find the ith:"<<endl;
cout<<l.get(3)<<endl;
cout<<"the loc of 15"<<endl;
cout<<li.loc(15)<<endl;
cout<<"the loc of 15:"<<endl;
cout<<l.loc(15)<<endl;
li.insert(3,100);
cout<<"the new after insert:"<<endl;
li.prt();
l.insert(3,100);
cout<<"the new after insert:"<<endl;
l.prt();
li.dele(3);
cout<<"the new after dele:"<<endl;
li.prt();
l.del(3);
cout<<"the new after dele:"<<endl;
l.prt();}
catch(string&s){
cout<<s<<endl;
}
system("pause");
return 0;}
两者的比较:
一、时间性能比较:
是指基于某种存储结构的算法时间复杂度。类如取出线性表内任意某个元素,使用顺序表快一点时间性能O(1),而链式表只能从表头开始依次向后扫描直至特定位置O(n);但是在进行相应插入与删除操作时候,在给出该处指针以后,增删所需时间O(1),而顺序表需平均移动一半元素,时间性能O(n),这对于大规模线性表来说,是不可忍受的。
二、空间性能比较:
首先定义存储密度:存储密度=(数据域占用的存储量)/(整个节点占用的存储量)
顺序表存储密度为1,而链式表数据域和指针域各占一部分节点,从这一层来说,顺序表更好;但是顺序表需要预先静态分配一定长度的存储空间,如果事先不知道线性表规模,会面临预分配过剩导致的浪费或者预分配过少导致的碎片,而单链表无需预分配。根据需要动态产生即可。故当线性表规模小或者规模已知时候用顺序表,否则用单链表。