数据结构 第二章 线性表

2.1 线性表的逻辑结构

2.1.1 线性表的定义

       线性表简称表,是n(n>=0)个具有相同类型的数据元素的有限序列,线性表中数据元素的个数称为线性表的长度。长度等于零时称为空表,一个非空表通常记为:L=(a1,a2,......,an) 其中,ai(1>=i<=ni)称为数据元素,下脚标i表示该元素在线性表中的位置或序号,称元素ai位于表的第i个位置,或称ai是表中的第i个元素。

2.1.2 线性表的抽象数据类型定义

     

 

 

2.2 线性表的顺序存储结构及实现

2.2.1线性表的顺序存储结构-----顺序表

       线性表的顺序存储结构称为顺序表。

       顺序表是用一段地址连续的存储单元依次存储线性表的数据元素。

        C++中数组的下标是从0开1始的,而线性表中元素的序号是从1开始的,也就是说,线性表中第i个元素存储在数组中下标为i-1的位置。

       线性表中数据元素的存储地址是其序号的线性函数,只要确定了存储顺序表的起始地址,计算任意一个元素的存储地址的时间是相等的,具有这一特点的存储结构称为随机存取。

2.2.2 顺序表的实现

 顺序表的声明:

const int MaxSize=100; 

template <class DataType>           //模板类

class SeqList

{

 public: 

     SeqList( ) ;                                 //构造函数

     SeqList(DataType a[ ], int n);      

     ~SeqList( ) ;                               //析构函数

     int Length( );

     DataType Get(int i);

     intLocate(DataType x );

     void Insert(int i, DataType x); 

     DataType Delete(int i);       

 private:

     DataType data[MaxSize];

     int length;

};

算法设计的一般步骤:

第一步:确定入口(已知条件)、出口(结果);

第二步:根据一个小实例画出示意图;

第三步:① 正向思维:选定一个思考问题的起点,逐步提出问题、解决问题;② 逆向思维:从结论出发分析为达到这个结论应该先有什么;③正逆结合;

第四步:写出顶层较抽象算法,分析边界情况;

第五步:验证第四步的算法;

第六步:写出具体算法;

第七步:进一步验证,手工运行

1.构造函数

template <class DataType

SeqList<DataType>::SeqList(DataType a[ ], int n)

       if (n > MaxSize) throw "参数非法";

       for (i = 0; i < n; i+ +) 

             data[i] = a[i];

       length = n;

 }

2.按位查找算法

template <class DataType

DataTypeSeqList<DataType>::Get( inti )

{

    if (i >= 1 && i <= length)return a[i-1];

 }

 

3.按值查找

template <class DataType

intSeqList<DataType>::Locate(DataType x)

{

     for (i = 0; i < length; i++)

         if (data[i] == x) return i + 1;

     return 0;         

}

 

4.插入算法

template<class DataType

void SeqList<DataType>::Insert(inti, DataType x)

{

      if (length >= MaxSize) throw "上溢";

      if (i < 1 || i > length + 1) throw "位置";

      for (j = length; j >= i; j--)

           data[j] = data[j-1];

      data[i-1] = x;

      length++;

}

2.3线性表链接存储结构及实现

2.3.1单链表

1.单链表的存储方法

    单链表是用一组任意的存储单元存放线性表的元素。

    存储思想:用一组任意的存储单元存放线性表的元素。

    存储特点:

    (1) 逻辑次序和物理次序不一定相同。

    (2) 元素之间的逻辑关系用指针表示。

    头指针:指向第一个结点的地址。

    尾标志:终端结点的指针域为空。

2.单链表的实现

单链表类的声明:

template<class DataType>

classLinkList

{  

public:

     LinkList( );

     LinkList(DataType a[ ], int n);

     ~LinkList( );

     int Length( );         

     DataType Get(inti);          

     int Locate(DataType x);      

     void Insert(inti, DataType x);  

     DataType Delete(inti);       

     void PrintList( );          

private:

     Node<DataType>*first;

};

3.遍历操作

核心操作(关键操作):工作指针后移。

template <class DataType>

void LinkList<DataType> :: PrintList( )

{

     p =first->next;

     while (p != NULL)

     {

         cout << p->data;

         p = p->next;  

     }

}

4.按值查找

(1)工作指针p初始化; 累加器count初始化;

(2) 重复执行下述操作,直到p为空:

    i工作指针p后移;

    iicount++;

(3)返回累加器count的值;

template <class DataType

intLinkList<DataType>:: Locate(DataType x)

{

    p =first->next;  count = 1;        

    while (p != NULL)   

    {

        if (p->data== x) return count;     //查找成功,返回序号

        p = p->next;                  

        count++;

    }

    return 0;                                          //退出循环表明查找失败

}

 

5.插入操作

 (1)工作指针p初始化;            

 (2)查找第i-1个结点并使工作指针p指向该结点;

 (3)若查找不成功,则插入位置不合理,抛出插入位置异常;

     否则,

     i 生成一个元素值为x的新结点s

     ii 将新结点s插入到结点p之后;

template <class DataType

 void LinkList<DataType> :: Insert(inti, DataType x)

 {

      p = first ; count= 0;             //工作指针p应指向头结点

      while (p != NULL && count < i - 1)     //查找第i – 1个结点

     {

          p = p->next;                  

          count++;

     }

     if (p == NULL)throw "位置";      //没有找到第i – 1个结点

    else {

        s = newNode;  s->data = x;         //申请一个结点s

        s->next =p->next; p->next = s;   //结点s插入结点p之后

    }

 }

 

6.构造函数

template <class DataType

LinkList<DataType> :: LinkList(DataType a[ ], int n)

{

    first = newNode;                        //生成头结点

    r = first;                                       //尾指针初始化

    for (i = 0; i < n; i++)

    {

        s = new Node;s->data = a[i];       

        r->next = s; r = s;                

    }

    r->next =NULL;       

}

7.删除操作

 (1)工作指针p初始化;

 (2)查找第i-1个结点并使工作指针p指向该结点;

 (3)若p不存在或p不存在后继结点,则抛出位置异常;

     否则,

         i暂存被删结点和被删元素值;

         ii 摘链,将结点p的后继结点从链表上摘下;

         iii 释放被删结点;

         iiii 返回被删元素值;

算法为:

template <class DataType

DataTypeLinkList<DataType>:: Delete(inti)

{

     p = first ; count= 0;           

     while (p != NULL && count < i - 1)

     {

         p = p->next;

         count++;

     }

     if (p == NULL ||p->next == NULL) throw "位置";

     else {

         q =p->next; x = q->data;        

         p->next =q->next;             

         delete q;return x;

     }

}

8.析构函数

template <class DataType>

LinkList<DataType> :: ~LinkList( )

{

     while (first !=NULL)

     {

         q =first;                

         first = first->next;        

         delete q;   

     }

}

2.3.2 循环链表

在单链表中,如果将终端结点的指针域由空指针为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为循环单链表,简称循环链表。

2.3.3 双链表

双链表:单链表的每个结点中再设置一个指向其前驱结点的指针域

定义结点结构:

template <class DataType>

structDulNode

{

     DataType data;

     DulNode<DataType> *prior, *next;

};

2.4顺序表和链表的比较

1.顺序表采用顺序存储结构,即用一段地址连续的存储单元依次存储线性表的数据元素,数据元素之间的逻辑关系通过存储位置来实现。
2.链表采用链接存储结构,即用一组任意的存储单元存放线性表的元素,用指针来反映数据元素之间的逻辑关系。

结论:

⑴若线性表需频繁查找却很少进行插入和删除操作,或其操作和元素在表中的位置密切相关时,宜采用顺序表作为存储结构;若线性表需频繁插入和删除时,则宜采用链表做存储结构。

⑵当线性表中元素个数变化较大或者未知时,最好使用链表实现;而如果用户事先知道线性表的大致长度,使用顺序表的空间效率会更高。

总之,线性表的顺序实现和链表实现各有其优缺点,不能笼统地说哪种实现更好,只能根据实际问题的具体需要,并对各方面的优缺点加以综合平衡,才能最终选定比较适宜的实现方法。

 

 

 

 

 

 

 

 

   

 

 

 

 

 

 

      

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值