数据结构笔记——第二章线性表

来源:互联网 发布:buy.apple mac china 编辑:程序博客网 时间:2024/04/29 13:37

   2.1  线性表的逻辑结构

     2.1.1  线性表的定义

             线性表:简称表,是n个具有相同类型的数据元素的有限序列。

            长度:线性表中数据元素的个数。

             空表:长度为0;非空表记作:L=(a1,a2,....,an)

           任意一对相邻的数据元素ai-1和ai(1<i<=n)之间存在序偶 关系<ai-1,ai>,ai-1称为ai的前驱,ai称为ai-1的后继。

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

            线性表表示一个相当灵活的数据结构,对线性表的数据元素不仅可以进行存取访问,还可以进行插入和删除       作.其抽象数据类型定义:

            ADT  List

            Date

            Operation

            InitList     功能:线性表初始化

            DestroyList 功能:销毁线性表

            Length     功能:求线性表的长度

            Get        功能:按位查找,在线性表中查找序号为i的数据元素

            Locate     功能:按值查找,在线性表中查找值等于x的元素

            Insert      功能:插入操作,在线性表的第i个位置插入一个新元素x

            Delete     功能:删除操作,删除线性表中的第i个元素

            Empty     功能:判空操作,判断线性表是否为空表

            PrintList   功能:遍历操作,按序号依次输出线性表中的元素

            endADT

           注意:对于不同的应用上述操作的接口可能不同,例如删除操作,若要求删除表中值为x的元素,则Delete操作的输入参数就不能是位置而应该是元素值。

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

          顺序表:线性表的顺序存储结构。它是用一段地址连续的存储单元依次存储线性表的数据元素。C++中数组下标是从0开始的,而线性表中元素的序号是从1开始的,即线性表中第i个元素存储在数组中下标为i-1的位置。顺序表中数据元素的存储地址是其序号的线性函数,只要确定了存储顺序表的起始地址,计算任意一个元素的存储地址时间是相等的(随机存取)。

        2.2.2顺序表的实现

               const int MaxSize=100;

               template<class T>

               class SeqList

              {

                 public:

                           SeqList(){length=0;}

                           SeqList(T int a[],int n);

                           ~SeqList(){}

                           Int Length(){return length;}

                           T Get(int i);

                           void Insert(int i,T x);

                           T Delete(int i);

                           int Locate(T x);

                           void PrintList();

                private:

                          T data[MaxSize];

                           int length;

              };

           1、  构造函数

                   无参构造函数SeqList()创建一个空的顺序表,只简单地将顺序表的长度length初始化0 

                       

              有参构造函数SeqList(T a[],int n)需要将给定的数组元素作为线性表的数据元素顺序表中,并将传入的元素个数作为顺序表的长度。

             

    

            顺序表有参构造函数SeqList

              template<class T>

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

              {

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

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

                   data[i]=a[i];

                   length=n;

               }

            2、  求线性表的长度

                 只需要返回变量length的值

           3、  查找操作

            (1)、按位查找:算法的时间复杂度为O(1)     

       顺序表按位查找算法Get

            template<class T>

           T SeqList<T>::Get(int i)

          {

               if(i<1 && i>length) throw”查找位置非法”;

                else return data[i-1];

           }

             (2)、按值查找:如果成功,返回元素序号(不是下标);不成功返回查找失败的标志“0”;平均时间性能是On)。

       顺序表按值查找算法Locate

            template<class T>

            int SeqList<T>::Locate(T x)

          {

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

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

                 return 0;

            }

          4、插入操作

              

 

              注意:元素移动的方向必须从最后一个元素开始移动,直到将第i个元素后移为止,然后新元素插入位置i处。若表满则上溢异常;若插入不合理则位置异常。

     顺序表插入算法Insert

         template<class T>

         void SeqList<T>::Insert(int i,T 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++;

       }

            注意:元素移动的方向必须从第i+1个元素开始移动,直至将最后一个元素前移为止,并且在移动元素之前要取出被删除元素。若表空则下溢异常,若删除位置不合理则异常。

      顺序表删除算法Delete

           Template<class T>

           T SeqList<T>::Delete (int i)

          {

                if (length==0)throw"下溢";

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

                    x=data[i-1];

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

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

                     length--;

                     return x;

          }

           算法的平均时间复杂度为On)。

          6、遍历操作

       顺序表遍历算法PrintList

             Template<class T>

             void SeqList<T>::PrintList()

           {

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

                  cout<<data[i];

            }

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

         2.3.1单链表

        1、单链表的存储方法

       单链表:用一组任意的存储单元存放线性表的元素,可连续可零散分布。

        指针:为了能正确表示元素之间的逻辑关系,每个存储单元在存储数据元素的同时,还必须存储其后继元素所在的地址信息,此地址信息为指针。

        

         C++的模板机制

         Template<class T>

          class LinkList

        {

               public:

                        LinkList();

                        LinkList(T a[],int n);

                       ~LinkList();

                       int Locate(T x);

                       T Get(int i);

                       Int Length();

                       void Insert(int i,T x);

                        T Delete(int i);

                        void PrintList();

             private:

                        Node<T> *first;

             };

 

              在单链表中,结点p由两个域组成:存放数据元素的部分和存放后继结点地址的指针部分,分别用p->datap->next来标识,且它们各有自己的值:p->data的值是一个数据元素,p->next的值是一个指针,单链表的操作必须从头指针开始进行,通常设置一个工作指针p,当指针p指向某结点时执行相应的处理,然后将指针p修改为指向其后继结点,直到pNULL为止。

         1、  遍历操作

         单链表遍历算法PrintList

          template<class T>

          void LinkList<T>::PrintList()

        {

                 p=first->next;

                 while(p!=NULL)

                {

                       cout<<p->data;

                       p=p->next;

                 }

          }

           时间复杂度为On

          注意:工作指针p后移不能写作p++,因为单链表的存储单元可能不连续。

          2、求线性表的长度

           求线性表长度的算法

            template<class T>

            void LinkList<T>::Length()

          {

                   p=first->next;

                   count=0;

                    while(p!=NULL)

                    {

                           p=p->next;

                           count++;

                     }

                   return count;

             }

             时间复杂度为On

           2、  查找操作

           (1)、按位查找

         单链表按位查找算法Get

                template<class T>

                T LinkList<T>::Get(int i)

               {

                            p=first->next;

                            count=1;

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

                            {

                                          p=p->next;

                                           count++;

                              }

                               if(p==NULL)throw”位置”;

                              else return p->data;

                }

              平均时间性能为O(n)

    (2)、按值查找

             单链表按值查找算法Locate

              template<class T>

              int LinkList<T>::Locate(T x)

            {

                 Node<T>*p=first->next;

                 int count=1;

                while(p!=NULL)

               {

                         if(p->data==x)

                         return count;

                         p=p->next;

                        count++;

               }

              return 0;

          }

           平均时间性能为O(n)

         4、插入操作

           单链表插入算法Insert

           template<class T>

           void LinkList<T>::Insert(int i,T x)

          {

                 p=first

                 count=0;

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

                {

                       p=p->next;

                       count++;

                 }

                if(p==NULL)throw"位置";

                else

               {

                    s=new Node<T>;

                    s->data=x;

                    s->next=p->next;

                    p->next=s;

              }

       }

           时间复杂度为O(n)

        5、构造函数

           无参构造函数LinkList

           template<class T>

           LinkList<T>::LinkList()

           {

                 first=new Node;

                first->next=NULL;

            }

           有参构造函数LinkListT a[],int n)有两种构造方法:头插法和尾插法

          (1)、头插法

       头插法建立单链表LinkList

             template<class T>

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

             {     

                    first=new Node;

                    first->next=NULL ;

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

                  {

                        s=new Node;

                        s->data=a[i];

                        s->next=first->next;

                        first->next=s;

                  }

             }

         (2)、尾插法

             尾插法建立单链表LinkList

             template<class T>

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

            {

                      first=new Node;

                      r=first;

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

                    {

                            s=new Node;

                            s->data=a[i];

                            r->next=s;

                            r=s;

                   }

                    r->next=NULL;

           }

          6、  删除操作

           单链表删除算法Delete

               template<class T>

               T LinkList<T>::Delete(int i)

              {

                    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;

                  }

              }

           时间复杂度为On

        7、析构函数

         单链表析构函数算法~LinkList

           template<class T>

           LinkList<T>::~LinkList()

           {

                 while(first!=NULL)

                 {

                           q=first;

                           first=first->next;

                           delete q;

                  }

            }

    2.3.2循环链表

       

           单链表的首尾相接,将终端结点的指针域由空指针改为指向头结点,构成单循环列表,简称循环列表。

        2.3.3双链表

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

 

                   Data为数据域,存放数据元素

                   Prior为前驱指针域,存放该结点的前驱结点的地址

                  Next为后继指针域,存放该结点的后继结点的地址

           采用C++模板机制

               template<class T>                                                                 

              struct DulNode

             {

                T data;

                DulNode<T>*prior,*next;

             };

           设指针p指向循环双链表中某一结点,则循环双链表具有以下对称性:

             (p->prior->next=p=(p->next)->prior

        1、  插入

                在结点p的后面插入一个新结点s,需要修改4个指针

             1s->prior=p;

             2) s->next=p->next;

            3) p->next->prior=s;

           4)p->next=s;

          注意指针修改的相对顺序。

         2、  删除

                  设指针P指向待删除结点,其操作

                1)    (p->prior->next=p->next;

                2)    (p->next)->prior=p->prior;

       2.4顺序表和链表的比较

          2.4.1 时间性能的比较

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

         2.4.2 空间性能比较

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

      2.5 线性表的其他存储方法        

         静态链表:用数组来表示单链表,用数组元素的小标来模拟单链表的指针。

          其结构定义:

           const int MaxSize=100;

           template<class T>

          struct sNode

         {

              T data;

              int next;

        }SList[MaxSize];

         间接寻址:将数组和指针结合起来的一种方法,它将数组中存储数据元素的单元改为存储指向该元素的指针。

                                                                         习题

 

1、

   1)对于顺序表,在等概率情况下,插入和删除一个元素平均需移动(表长的一半)个元素,具体移动元素的个数与(表长)和(该元素在表中的位置)有关。

   2)顺序表中第一个元素的存储地址是100,每个元素的长度为2,则第五个元素的存储地址是(108

  3)设单链表中指针P指向结点A,若要删除A的后继结点,则需修改指针的操作为((p->next)->next)

   4)单链表中设置头结点的作用(为了运算方便

 5)非空的单循环链表由头指针head指示,则其尾节点满足(p->next=head)

 6)在由为指针rear指示的单循环链表中,在表尾插入一个s的操作序列是(o(1));删除开始结点的操作序列为(o(n))

  7)一个具有n个结点的单链表,在指针p所指结点后插入一个新结点的时间复杂度为s->next=rear->next;rear->next=s;rear=s)在给定值为x的结点后插入一个新结点需要先查找值为x的结点,所以时间复杂度为q=rear->next->next;rear->next->next=q->next;delete q;)

 8)可由一个尾指针唯一确定的链表有(循环单链表)、(循环双链表)、(双链表)。

 

 

 

          

 

 

0 0
原创粉丝点击