SDUST 2020/数据结构/期末集合.part1


以下内容仅代表个人的想法,整理自用,如有错误欢迎指正批评


1 绪论 && 数据结构基本概念

数据结构的研究内容为:非数值计算的程序设计问题中计算机的操作对象以及它们之间的关系和操作

01基本概念

1. 数据(data):所有能输入到计算机中去的描述客观事物的符号。

   ?数值性数据

   ?非数值性数据(多媒体信息处理)

2. 数据元素(data element)     数据的基本单位,也称结点(node)或记录(record),具有完整的意义 。

3. 数据项(dataitem)    有独立含义的、不可分割的数据最小单位,也称域(field)。

     以上三者之间的关系:数据>数据元素>数据项。例如:学生表>个人记录>学号、姓名....

4. 数据对象:相同特性的数据元素的集合,是数据的一个子集

5. 数据结构 : 相互之间存在一种或多种特定关系的数据元素的集合

02数据结构的两个层次

1.逻辑结构:数据元素间抽象化的相互关系,与数据的存储无关,独立于计算机,它是从具体问题抽象出来的数学模型。
   划分方法有两种

    ①:

  •    线性结构——有且仅有一个开始和一个终端结点,并且所有结点都最多只有一个直接前趋和一个后继。
  •    非线性结构——一个结点可能有多个直接前趋和直接后继。

                       常用的线性结构有:线性表,栈,队列,双队列,数组,串。
                       常见的非线性结构有:二维数组,多维数组,广义表,树(二叉树等),图,堆。

     ②:

             集合、线性结构、树形结构、图形结构

              注:数据的逻辑结构 与数据元素本身的形式、内容、相对位置、个数均无关

2.存储结构(物理结构) --数据元素及其关系在计算机存储器中的存储方式。

     顺序存储结构:借助元素在存储器中的相对位置来表示数据元素间的逻辑关系

     链式存储结构:借助指示元素存储地址的指针表示数据元素间的逻辑关系

3.所谓逻辑结构是指反映数据元素之间的逻辑关系的数据结构,其中逻辑关系指的是数据元素前后件的关系,而他们之间的关系与他们在计算机当中的存储位置无关,实际上可以认为逻辑结构是人们为了解决问题而抽象出来的模型。知道逻辑结构是一种模型,而存储结构是实际在计算机中的存储时的结构。

03算法和算法分析

1.定义:一个又穷的指令集,为解决某一特定任务规定了一个运算序列

   特性:有穷性、确定性、可行性、有输入有输出

   算法的评价从四个维度来确认:正确性、可读性、健壮性(对不正确的情况作出适当的反应和处理)、高效性

2.算法效率的度量

     ¤ 事后统计:利用计算机内的计时功能,不同算法的程序可以用一组或多组相同的统计数据区分

               缺点:  ①必须先运行依据算法编制的程序

                         ②所得时间统计量依赖于硬件、软件等环境因素掩盖算法本身的优劣

     ¤ 事前分析估算法

          一个高级语言在计算机上运行所消耗的时间取决于:依据的算法选用何种策略 || 问题的规模 || 程序语言 || 编译程序产生及其代码质量 || 机器执行指令的速度

      ¤ 时间复杂度

04 时间复杂度

一般情况,算法中基本操作重复的次数是关于 问题规模n 的某个函数f(n)(频度)

算法的时间量度记作T(n)=O(f(n)),即为时间复杂度。

简单来讲,计算时间复杂度,就是根据代码,将重复次数用一个含有 问题规模n 的代数式表示出来。

①O(1)类型

   如果算法的执行时间不随着问题规模n的增加而增长,即使算法中有上千条语句,其执行时间也不过是一个较大的常数。此类算法的时间复杂度是O(1)。

     eg.   

x=0;
for(i=0;i<1000;i++)
         x+=i;

②O(n^a)类型

    eg1. 

 for(i=0;i)

               for(j=0;j)

                     x+=1;

           结果是   Σ(i=0—n)Σ(j=0—n)*1=n*n

     eg2

         if ( A > B )

            { for ( i=0; i100; i++ )

                for ( j=N*N; j>i; j-- )

                     A += B; }

            else

           { for ( i=0; i2; i++ )

               for ( j=N*3; j>i; j-- )

                  A += B; }

          选取需要时间最长的那个循环,显然是if里面的     n^5

    eg3.

         int func ( int n )

            { int i = 0, sum = 0;

                while ( sum < n )

                     sum += ++i;

               return i; }

③O(log an)类型

    eg. 

for (int i = 1; i <= n; i *= c)

           a = a + 1;

             设频度f(n),则有  c^f(n)*1<=n,取等号时计算,得 f(n)=O(log cn)

             同理,i执行 i/=c 的时候也是成立的:

 for (int i = n; i > 0; i /= c) 
        { a = a + 1;}

         设频度f(n),则有(1/c)^f(n)*n>0,因为i是int型,取(1/c)^f(n)*n=1时计算,得 f(n)=O(log cn)

④其它类型

    eg.

for(i=0; i)

       for(j=i; j>0; j/=2)

              printf(“%d\n”, j);

常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)

05选择

          1、 数据在计算机内存中的表示是指(A) 。
                 A.数据的存储结构
                 B.数据结构
                 C.数据的逻辑结构
                 D.数据元素之间的关系

          2、 树形结构中元素之间存在()关系。 一对多
          3、 算法的时间复杂度取决于( )。D
                    A.问题的规模           B.待处理数据的初态
                    C.计算机的配置       D.A和B

           4、以下说法正确的是( )。D
                   A.数据元素是数据的最小单位
                   B.数据项是数据的基本单位
                   C.数据结构是带有结构的各数据项的集合
                   D.一些表面上很不相同的数据可以有相同的逻辑结构

           5、数据的基本单位是()。数据元素

           6、下面代码段的时间复杂度是() n^0.5

x=n; //n>1
y=0;
while( x≥(y+1)*(y+1) )
    y++;

            7、下面代码段的时间复杂度是() nlogn

for(i=0; i)
  for(j=i; j>0; j/=2)
     printf(“%d\n”, j);

            8、下面代码段的时间复杂度是() n^4

if ( A > B ) {
    for ( i=0; i100; i++ )
        for ( j=N*N; j>i; j-- )
            A += B;
}
else {
    for ( i=0; i2; i++ )
        for ( j=N*3; j>i; j-- )
            A += B;
}

2 线性表

  线性表是一种简单的线性结构,它的基本特征为:在数据元素的非空有限中:

   集合中必存在唯一的“第一元素”和“最后元素”

   除最后元素外,都有唯一后继;除第一元素外,都有唯一前驱

 01 顺序表

     如果我们知道想要访问的是顺序表中的第几个元素,我们就可以通过基地址加上偏移量来直接访问我们想要访问的数据元素,因此我们说顺序表是随机存储。

     在顺序表当中存在两个域,一个是指针域用来指向基地址,另一个就是表示顺序表当前长度的域是一个整型的变量。

    题目:

    1、若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用顺序表存储最节省时间。T

    2、对于顺序存储的长度为N的线性表,删除第一个元素插入最后一个元素的时间复杂度分别对应为O(1)和O(N)。       F
           删除第一个元素和插入最后一个元素的时间复杂度分别对应为O(N)和O(1)            所有元素在删除之后要向后移;新插入元素直接输入a[N]     3、对于顺序存储的长度为N的线性表,访问结点增加结点的时间复杂度分别对应为O(1)和O(N)。                                T       4、(neuDS)顺序存储的线性表不支持随机存取。                                                                                                                 F
     5、在N个结点的顺序表中,算法的时间复杂度为O(1)的操作是:A            A.访问i个结点(1iN)和i个结点的直接前驱(2iN)  //直接访问a[i]和a[i-1]即可            C.删除i个结点(1iN)                                                          //删除节点需要前移后续元素
           D.将N个结点从小到大排序                                                        //肯定不是O(1)      6、(neuDS)要将一个顺序表{a?0??,a?1??,……,a?n?1??}中第i个数据元素a?i??(0≤i≤n-1)删除,需要移动( )个数据元素。            n-i-1               7、若长度为n的线性表采用顺序存储结构,那么删除它的第i个数据元素之前,需要它一次向前移动()个数据元素。n-i                          注意i是指位置不是下标      8、若长度为n的线性表采用顺序结构,在第i个数据元素之前插入一个元素,需要它依次向后移动()个元素。n-i+1                      注意i是指位置不是下标      9、要将一个顺序表{a?0??,a?1??,……,a?n?1??}中第i个数据元素a?i??(0≤i≤n-1)删除,需要移动( )个数据元素。n-i-1            这里的i是指下标不是序号,第i个数的下标应该是i-1才对            希望出题人重新学习义务教育标准课程语文,脑瘫不要紧,脑瘫不治才可怕?
     10、线性表L=(a1, a2 ,……,an )用一维数组表示,假定删除线性表中任一元素的概率相同(都为1/n),则删除一个元素平均需要移动元素的个数是()。       (n-1)/2     11、顺序表中第一个元素的存储地址是100,每个元素的长度为2,则第5个元素的地址是( )。108

            100+2(5-1)=108

     12、将两个结点数都为N且都从小到大有序的单向链表合并成一个从小到大有序的单向链表,那么可能的最少比较次数是:N

           最少次情况举例:1234    5678 只需要把5和1234比较一遍即可

    

02 单链表

    用一组地址任意的存储单元存放线性表中的数据元素,有 元素(数据元素的映像)+指针(指示后继元素存储位置)=结点, 以"结点的序列"表示线性表,称为链表。

                  以线性表中第一个数据元素a1的存储地址作为线性表的地址,称作线性表的头指针;

                  有时为了操作方便,在第一个结点之前虚加一个"头节点",以指向头结点的指针为头指针。

     定义:
typedef int ElemType;
struct LNode
{
   ElemType data;
   LNode *next;
};
typedef LNode *LinkList;
  • ElemType为对应的数据域的数据类型,不仅仅是基本的数据类型,也可以复杂的数据类型。
  • next即为指向直接后继存储位置的指针
  • LNode *类型我们用来指向单个节点
LinkList L;

   这样就声明了一个链表L,L指向头结点(这里讨论带头结点的单链表),实际上不管是带头结点还是不带头结点,L永远都指向链表的第一个元素。

    单链表初始化:

bool InitList(LinkList &L)
{
    L = new LNode();
    if(L != NULL)
        return true;
    else
        return false;
}

     申请成功也就是L不指向空返回true,反之申请不成功L指向空返回false。

    单链表中按位置查找元素:

ElemType GetElem(LinkList L, int pos)
{
    int j = 1;
    L = L->next;          //有头结点
    while(L && j < pos)  //顺指针查找,直到L指向第pos个元素
    {
        L = L->next;
        j++;
    }
 
    if(!L || j > pos)   //不存在第pos个元素
        return -1;      //错误返回值视情况而定
    return L->data;     //返回被查元素
}

    单链表中按数值查找元素:

int LinkFind(LinkList L, ElemType e)
{
    int j = 1;
    L = L->next;
    while(L && L->data != e)
    {
        L = L->next;
        j++;
    }
 
    if(!L)
        return -1;
    return j;      //返回的是该数的位置
}

   单链表元素插入:

bool ListInsert(LinkList &L, int pos, ElemType e)  //在第pos的位置插入元素e
{
    int j = 0;
    while(L && j < pos - 1)
    {
        L = L->next;
        j++;
    }
 
    if(!L || j > pos - 1)
        return false;
 
    LNode *s = new LNode(e);
//s=(LinkList)malloc(sizeof(LNode)) s
->next = L->next; L->next = s; return true; }

  单链表元素删除:

bool ListDelete(LinkList &L, int pos)
{
    int j = 0;
    while(L && j < pos - 1)
    {
        L = L->next;
        j++;
    }
 
    if(!L || j > pos)
        return false;
 
    LNode *p = L->next;
    L->next = L->next->next;
    delete p;
 
    return true;
}

bool Ldelete (LinkLinst &L,int pos,int &e)
{
    int j=0;
    LNode *p=L;
    while(p->next&&j1)
    {
        p=p->next;
        j++;
    }
    if(!(p->next)||j>i-1)
        return false;
    LNode *q;
    q=p->next;
    e=q->data;
    p->next=q->next;
    free(q);
    return true;
}
  • 如果删除失败成功true,否则返回false。
  • 要删除第i个结点我们首先要获取第i个结点的直接前驱,也就是第i-1一个结点。
  • 将ai-1的next指针指向ai的下一个结点(L->next = L->next->next)即跨过了ai,相当于删除。同时必须要清空ai所占的内存,于是用结点指针p指向ai方便删除。

题目:

       1、设h为不带头结点的单向链表。在h的头上插入一个新结点t的语句是:

         t->next=h; h=t;

   2在单链表中,若p所指的结点不是最后结点,在p之后插入s所指结点,则执行

                s->next=p->next; p->next=s;

    3带头结点的单链表h为空的判定条件是:

         h->next == NULL;

    4、(neuDS)在单链表中,增加一个头结点的最终目的是为了

       5、以下关于链式存储结构的叙述中,(C)是不正确的。
        A.结点除自身信息外还包括指针域,因此存储密度小于顺序存储结构
        B.逻辑上相邻的结点物理上不必邻接
        C.可以通过计算直接确定第i个结点的存储地址

        D.插入、删除运算操作方便,不必移动结点

      6、不带表头附加结点的单链表为空的判断条件是头指针head满足条件

          head==NULL

      7、对于一非空的循环单链表,hp分别指向链表的头、尾结点,则有:

         p->next == h

   8、在双向循环链表结点p之后插入s的语句是:



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

 9、在双向链表存储结构中,删除p所指的结点,相应语句为:       p->prior->next=p->next; p->next->prior=p->prior;  10、在一个含有n个结点的有序单链表中插入一个新结点,使单链表仍然保持有序的算法的时间复杂度是( )      O(n)  11、以下关于链式存储结构的叙述中,()是不正确的。C       A.结点除自身信息外还包括指针域,因此存储密度小于顺序存储结构       B.逻辑上相邻的结点物理上不必邻接
      C.可以通过计算直接确定第i个结点的存储地址       D.插入、删除运算操作方便,不必移动结点
 12、某线性表中最常用的操作是在最后一个元素之后插入一个元素和删除第一个元素,则采用什么存储方式最节省运算时间?
      仅有尾指针的单链表  13、将线性表La和Lb头尾连接,要求时间复杂度为O(1),且占用辅助空间尽量小。应该使用哪种结构?       带有尾指针单链表  14、在链表中若经常要删除表中最后一个结点或在最后一个结点之后插入一个新结点,则宜采用()存储方式。       用尾指针标识的循环单链表
 15、若某表最常用的操作是在最后一个结点之后插入一个结点或删除最后一个结点,则采用()存储方式最节省运算时间。       在表头附加结点的双循环链表    16、如果对线性表的运算只有4种,即删除第一个元素,删除最后一个元素,在第一个元素前面插入新元素,在最后一个元素的后面插入新元素,则最好使用()。C
      A.只有表尾指针没有表头指针的循环单链表     B.只有表尾指针没有表头指针的非循环双链表
      C.只有表头指针没有表尾指针的循环双链表     D.既有表头指针也有表尾指针的循环单链表
 17、如果对线性表的运算只有2种,即删除第一个元素,在最后一个元素的后面插入新元素,则最好使用()。B
      A.只有表头指针没有表尾指针的循环单链表     B.只有表尾指针没有表头指针的循环单链表
      C.非循环双链表                          D.循环双链表
 18、与单链表相比,双链表的优点之一是()
      A.插入、删除操作更加简单         B.可随机访问
      C.可以省略表头指针或表尾指针     D.顺序访问相邻结点更加灵活

03 对比

     顺序表的优点是查找方便,根据下标迅速定位,因此时间复杂度是1;但是插删的时候需要移动元素,因此时间复杂度是N

     链表的优点是插删方便,直接通过指针指向地址,不需移动其他元素

     在表的最后一个结点之后插入一个新结点或删除最后一个结点,最节省运算的方式是 带有尾指针的单循环 带有表头的双循环

04 程序

  3、两个有序链表的并集
#include
using namespace std;
typedef struct LNode              //链表
{
    int data;
    struct LNode *next;
} LNode,*List;
void CreatList(List &s)           //创建链表(输入数值)
{
    LNode *p,*q;
    s=(LNode*)malloc(sizeof(LNode));
    q=s;
    int x;


    while(scanf("%d",&x)!=EOF)
    {
        if(x==-1)
        {
            return ;

        }
        p=(LNode*)malloc(sizeof(LNode));
        p->next=NULL;
        p->data=x;
        q->next=p;
        q=p;
    }
}
List Plus(List s1,List s2)    //合成:返回一个新链表
{
    List S;
    S=(LNode*)malloc(sizeof(LNode));
    S->next=NULL;
    
    LNode *z=S;
    s1=s1->next;
    s2=s2->next;
    
    while(s1!=NULL&&s2!=NULL)
    {
        if(s1->data<=s2->data)     //合成新链表:取小数输入
        {
            z->next=s1;
            z=s1;
            s1=s1->next;
        }
        else
        {
            z->next=s2;
            z=s2;
            s2=s2->next;
        }
    }
    if(s1 != NULL)
        z->next = s1;
    if(s2 != NULL)
        z->next = s2;
    return S;

}
void PrintfList(List s)     //输出链表
{
    if(s->next==NULL)
    {
        printf("NULL");
        return ;
    }
    s=s->next;
    while(s!=NULL)
    {
        if(s->next==NULL)
        {
            printf("%d",s->data);
        }
        else
        {
            printf("%d ",s->data);
        }
        s=s->next;
    }
}
int main()
{
    List s1,s2,S;
    CreatList(s1);
    CreatList(s2);
    S=Plus(s1,s2);
    PrintfList(S);
}

05 主要函数总结

typedef struct LNode//定义
{
    int data;
    LNode *next;
} LNode,*LinkList;

void CreatList(LinkList &L)//正序输入创建
{
    L=(LinkList)malloc(sizeof(LNode));
    LNode *p=L;
    LNode *num;

    int x;
    while(scanf("&d",&x)!=EOF)
    {
        if(x==-1)
            return ;
        num=(LinkList)malloc(sizeof(LNode));
        num->next=NULL;
        num->data=x;
        p-next=num;
        num=p;
    }
}

void CoutList(LinkList L)//输出链表元素
{
    if(L->next==NULL)
    {
        printf("NULL");
        return ;
    }
    L=L->next;
    while(L!=NULL)
    {
        if(L->next!=NULL)
            printf("%d ",L->data);
        else
            printf("%d",L->data);
    }
}

bool Ldelete(LinkList &L,int pos,int &e)//删除位置为pos的值
{
    int j=0;
    while(L&&j1)
    {
        j++;
        L=L->next;
    }
    if(!L||j>pos-1)
        return false;
    LNode *p;
    p->next=L->next;
    L->next=p->next;
    e=p->data;
    free(p);
    return true;
}
int GetElem(LinkList L,int pos,int &e)//获取位置为pos的值
{
    int j=0;
    while(L&&j1)
    {
        j++;
        L=L->next;
    }
    if(!L||j>pos-1)
        return -1;
    LNode *p;
    p->next=L->next;
    L->next=p->next;
    e=p->data;
    return e;
}

int GetPos(LinkList L,int &pos,int e)//获取第一个值为e的位置
{
    int j=1;//算位置:从1开始
    while(L&&L->data!=e)
    {
        j++;
        L=L->next;
    }
    if(!L||j>pos-1)
        return -1;
    return j;
}

List MergeList(LinkList L1,LinkList L2)//取交集
{
    List L;
    L=(LinkList)malloc(sizeof(LNode));
    L->next=NULL;
    LNode *p=L;
    L1=L1->next;
    L2=L2->next;
    while(L1!=NULL&&L2!=NULL)
    {
        if(L1.data<L2.data)
            L1=L1.next;
        else if(L1.data>L2.data)
            L2=L2.data;
        else
        {
            p->next=L1;
            p=L1;
            L1=L1->next;
            L2=L2->next;
        }
    }
    return L;
}

List Plus(List s1,List s2)    //取并集
{
    List S;
    S=(LNode*)malloc(sizeof(LNode));
    S->next=NULL;

    LNode *z=S;
    s1=s1->next;
    s2=s2->next;

    while(s1!=NULL&&s2!=NULL)
    {
        if(s1->data<=s2->data)     //合成新链表:取小数输入
        {
            z->next=s1;
            z=s1;
            s1=s1->next;
        }
        else
        {
            z->next=s2;
            z=s2;
            s2=s2->next;
        }
    }
    if(s1 != NULL)
        z->next = s1;
    if(s2 != NULL)
        z->next = s2;
    return S;

}

3 栈

     栈作为一种限定性线性表,是将线性表的插入和删除运算限制在表的一端进行。栈是一种后进先出的线性表。

     通常将表中允许进行插入、删除操作的一端成为栈顶(Top),因此栈顶的当前位置是动态变化的,由一个栈顶指针的位置指示器指示;

     表的另一端为固定的一端,成为栈底(Bottom)。

    01选择:

       1、给定一个堆栈的入栈序列为{ 1, 2, ?, n },出栈序列为{ p?1??, p?2??, ?, p?n?? }。如果p?2??=n,则存在多少种不同的出栈序列?  

                    n-1

             这里的入栈指可以间断穿插出栈

             p2=n,即第二个出栈的数据元素是n,那么第一个出栈的数据元素则可以是{1,2,?,n-1}中的任何一个,所以存在的不同的出栈序列一种有n-1种。

       2、设一个堆栈的入栈顺序是1、2、3、4、5。若第一个出栈的元素是4,则最后一个出栈的元素必定是:

             1或者5

             注意考虑周全

       3、栈顶指针为ST的链栈中删除一个结点且用X保存被删结点的值,则执行:

           X= ST->data; ST = ST->next;

       4、设栈S和队列Q的初始状态均为空,元素a、b、c、d、e、f、g依次进入栈S。

            若每个元素出栈后立即进入队列Q,且7个元素出队的顺序是b、d、c、f、e、a、g,则栈S的容量至少是:

              至少是 3

       5、假设有5个整数以1、2、3、4、5的顺序被压入堆栈,且出栈顺序为3、5、4、2、1,那么为了获得这样的输出,堆栈大小至少为:

            4

       6、若元素a、b、c、d、e、f依次进栈,允许进栈、退栈操作交替进行,但不允许连续三次进行退栈工作,则不可能得到的出栈序列是:D

               A.b c a e f d     B.c b d a e f           7、设一个栈的输入序列是1、2、3、4、5,则下列序列中,是栈的合法输出序列的是?A
               A.3 2 1 5 4       B.5 1 2 3 4      C.4 5 1 3 2      D.4 3 1 2 5
       8、若一个栈的入栈序列为1、2、3、…、N,其输出序列为p?1??、p?2??、p?3??、…、p?N??。若p?1??=N,则p?i??为:               n-i+1        9、若一个栈的入栈序列为1、2、3、…、N,输出序列的第一个元素是i,则第j个输出元素是:                不确定       10、将5个字母ooops按此顺序入栈,则有多少种不同的出栈顺序可以仍然得到ooops?               5       11、从栈顶指针为ST的链栈中删除一个结点且用X保存被删结点的值,则执行:C
                A.X= ST->data;
                B.X= ST; ST = ST->next;
                C.X= ST->data; ST = ST->next;
                D.ST = ST->next; X= ST->data;        12、设栈S和队列Q的初始状态均为空,元素a、b、c、d、e、f、g依次进入栈S。若每个元素出栈后立即进入队列Q,                且7个元素出队的顺序是b、d、c、f、e、a、g,则栈S的容量至少是:3                栈的操作顺序是先进后出,即入队顺序=出队倒序;队列是先进先出,入队顺序=出队顺序                所以题目转为:能让元素以b、d、c、f、e、a、g出栈的栈的最小容量是?                a,b进,存在a,b,出b,剩a                c,d进,存在a,c,d,出d,c,剩a                e,f进, 存在a,e,f,出f,e,剩a                出a                进g,出g,结束        13、假设有5个整数以1、2、3、4、5的顺序被压入堆栈,且出栈顺序为3、5、4、2、1,那么为了获得这样的输出,堆栈大小至少为:4         14、若元素a、b、c、d、e、f依次进栈,允许进栈、退栈操作交替进行,但不允许连续三次进行退栈工作,则不可能得到的出栈序列是?D                A.b c a e f d            B.c b d a e f
               C.d c e b f a            D.a f e d c b         15、若一个栈的入栈序列为1、2、3、…、N,输出序列的第一个元素是i,则第j个输出元素是:不确定                  中间可以间断入出         16、线性表、堆栈、队列的主要区别是什么?B
                 A.线性表用指针,堆栈和队列用数组
                 B.堆栈和队列都是插入、删除受到约束的线性表
                 C.线性表和队列都可以用循环链表实现,但堆栈不能
                 D.堆栈和队列都不是线性结构,而线性表是
                      C:堆栈也可以是循环的          17、为解决计算机主机与打印机之间速度不匹配问题,通常设置一个打印数据缓冲区,主机将要输出的数据依次写入该缓冲区,                 而打印机则依次从该缓冲区中取出数据。该缓冲区的逻辑结构应该是?队列                     由于主机将要输出的数据依次写入缓冲区,而打印机则依次从缓冲区中取出数据打印,                     数据写入缓冲区的次序与缓冲区中取数据打印的次序是一致的,因此该缓冲区是一个队列结构。          18、若用大小为6的数组来实现循环队列,且当前frontrear的值分别为0和4。当从队列中删除两个元素,再加入两个元素后,frontrear的值分别为多少?                2和4          19、如果循环队列用大小为m的数组表示,且用队头指针front和队列元素个数size代替一般循环队列中的frontrear指针来表示队列的范围,                 那么这样的循环队列可以容纳的元素个数最多为:m         ?20、如果循环队列用大小为m的数组表示,队头位置为front、队列元素个数为size,那么队尾元素位置rear为:
                 (front+size-1)%m                  关键这是一个循环队列,r可能小于f,例如n为4时,元素个数有0、1、2、3,r可以为0,f为2,这样实际上有两个元素,但是以r-f得出来的是-2  

    02判断

            1、所谓“循环队列”是指用单向循环链表或者循环数组表示的队列。    F

                     理解一:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列

                     理解二:队列中含有front和rear两个指针,不同于单向链表

                     循环队列指的是后者,用数组表示的队列,利用求余数运算使得头尾相接

            2、在用数组表示的循环队列中,front值一定小于等于rear值        F

                    大于小于等于都有可能

            3、不论是入队列操作还是入栈操作,在顺序存储结构上都需要考虑"溢出"情况   T

    03程序

                   

    04栈与递归的实现(跳过)

        在定义一个过程或者函数时出现调用本过程或本函数的成分,称之为递归。若调用自身,称为直接递归;调用其它,称为间接递归

        何时使用递归:

                         ①定义是递归的,如求Fibonacci数列、求阶乘

                         ②数据结构是递归的,如之前的链表类型的定义

                         ③问题的求解的方法是递归的,如Hanoi问题:

 

void Hanoi(int n,char x,char y,char z)
{
//将塔座x上按直径由小到大且至上而下编号为1至n
//的n个圆盘按规则搬到塔座z上,y为辅助塔座
  if(n==1)
    move(x,1,z);
  else {
         Hanoi(n-1,x,z,y);
         //将x'上编号为1至n-1的圆盘移到y,z作辅助塔
         move(x,n,z);//将编号为n的圆盘从x移到z
         Hanoi(n-1,y,x,z);
         //将y上编号为1至n-1的圆盘移到z,x作辅助塔
   }
}

    05 主要函数总结

#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef char SElemType ;
typedef struct
{
    SElemType *base;
    SElemType *top;
    int stacksize;
} STACK;
int  Pop(STACK &S)         //出栈
{
    if(S.top==S.base)
        return 0;
    *S.top,S.top--;
    return 1;
}
int Push(STACK &S,char e)  //入栈
{
    if(S.top-S.base>=S.stacksize)
    {
        S.base = (SElemType*)realloc(S.base,(S.stacksize+STACKINCREMENT)*sizeof(SElemType));;

        if(!S.base)
        {
            return -1;
        }
        S.top=S.base+S.stacksize;
        S.stacksize+=STACKINCREMENT;
    }
    *S.top++=e;
    return 1;
}
int StackEmpty(STACK& S)   //判断是否栈空
{
    if(S.base == S.top)
        return 1;
    return -1;
}
int Gettop(STACK S,SElemType &e)  //返回栈顶元素
{
    if(S.top==S.base)
        return 0;
    e= *(S.top-1);
    return 1;
}
int InitStack(STACK &S)      //建立空栈
{
    S.base=(char *)malloc(STACK_INIT_SIZE*sizeof(char));
    if(!S.base)
        exit(-1);
    S.top=S.base;
    S.stacksize=STACK_INIT_SIZE;
    return 1;
}

附 期中题目

    01选择

            1、在双向循环链表结点p之后插入s的语句是:A

                A.s->prior=p; s->next=p->next; p->next->prior=s; p->next=s;
                B.s->prior=p; s->next=p->next; p->next=s; p->next->prior=s;
                C.p->next=s; s->prior=p; p->next->prior=s ; s->next=p->next;
                D.p->next->prior=s; p->next=s; s->prior=p; s->next=p->next;

            2、判断一个循环队列QU(最多元素为MaxSize)为空的条件是()。C

                A.QU.front == (QU.rear + 1) % MaxSize
                B.QU.front != QU.rear
                C.QU.front == QU.rear
                D.QU.front != (QU.rear + 1) % MaxSize

               在循环队列中,如果队列中有元素,则首尾指针不会指向同一个结点,如果首尾指针指向同一个结点,则说明队列中没有元素,因此为空。

           3、通常要求同一逻辑结构中的所有数据元素具有相同的特性,这意味着( )。C
                A.数据元素所包含的数据项的个数要相等
                B.数据在同一范围内取值
                C.不仅数据元素所包含的数据项的个数要相同,而且对应数据项的类型要一致
                D.每个数据元素都一样
           4、数组A[1..5,1..6]每个元素占5个单元,将其按行优先次序存储在起始地址为1000的连续的内存单元中,则元素A[5,5]的地址为:1140

                           

            5、下面代码段的时间复杂度是()。O(n2)

x=0;
for( i=1; i )
    for ( j=1; j<=n-i; j++ )
        x++;

            (n-1)+(n-2)+(n-3)+.........+(n-n)

            6、由两个栈共享一个向量空间的好处是( )。C

                  A.减少存取时间,降低下溢发生的机率
                  B.节省存储空间,降低下溢发生的机率
                  C.节省存储空间,降低上溢发生的机率
                  D.减少存取时间,降低上溢发生的机率

           7、某队列允许在其两端进行入队操作,但仅允许在一端进行出队操作。若元素a、b、c、d、e依次入此队列后再进行出队操作,则不可能得到的出队序列是:B
              A.d b a c e
              B.d b c a e
              C.e c b a d
              D.b a c d e

 


 

 

    02判断

              1、假设模式串是abababaab,则KMP模式匹配算法中的next[j] = 0 1 1 2 3 4 5 6 2   T

              2、在用数组表示的循环队列中,front值一定小于等于rear值。                                          F
                  rear在对max取余之后会从零开始,但这时front并不是零。所以会出现front>rear,( >,=,<三种情况都有可能出现)。

              3、对于某些算法,随着问题规模的扩大,所花的时间不一定单调增加。                           T

              4、链表的每个结点都恰好有一个指针。                                                                              F