服务于期末考试的数据结构与算法设计的知识点整理

本文详细介绍了数据结构中的二叉树概念,包括二叉搜索树、哈希表、二叉排序树和堆排序,以及图的存储结构如邻接矩阵和邻接表,特别讨论了二分查找和哈希冲突的解决方法。此外,还涵盖了排序算法如插入排序、冒泡排序、选择排序和快速排序的原理和实现。
摘要由CSDN通过智能技术生成

序论


基本概念和术语


数据

描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。

数据元素

组成数据的、有一定意义的基本单位,在计算机中通常作为整体处理。

人是人类的数据元素

数据项

一个数据元素可以由若干个数据项组成

数据项是数据不可分割的最小单位

数据对象

是性质相同 的数据元素的集合,是数据的子集

数据结构

是相互之间存在一-种或多种特定关系的数据元素的集合。

例题:

  • 数据结构是指数据及其相互之间的__‎。当结点之间存在M对N(M:N)的联系时,称这种结构为__‎_‎。联系 图

逻辑结构

数据对象中数据元素之间的相互关系

  • 集合结构

  • 线性结构

  • 树形结构

  • 图形结构

例题:

  • 下列关于数据结构的叙述中,正确的是( ).D

A. 数组是不同类型值的集合

B. 递归算法的程序结构比迭代算法的程序结构更为精炼

C. 树是一种线性结构

D. 用一维数组存储一棵完全二叉树是有效的存储方法

  • 数据的逻辑结构被分为‎_‎、_‎_‎和___‎__四种

上面就有答案~我懒得写

存储结构

数据的逻辑结构在计算机中的存储形式

例题:

  • 数据的物理结构被分为‎_‎、_‎_‎和__‎_‎__四种。

顺序 链表 索引 散列

顺序存储

数据元素存放在地址连续的存储单元里

例题:

  • 下述哪一条是顺序存储方式的优点?( )A

A.存储密度大‎ B.插入和删除运算方便

C. 获取符合某种条件的元素方便 D.查找运算速度快

链式存储

数据元素存放在任意的存储单元里,这组存储单元可以是连续的,也可以不连续。

数据在哪不重要,只要有一个指针存放相应的地址就能找到

算法


算法的基本概念

算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。

  • 对一个算法的评价,不包括如下( )方面的内容‎。 B

A.健壮性和可‎读性 B.并行性 C.正确性 D.时空复杂度

算法的特征

  • 输入输出

  • 有穷性

  • 确定性

  • 可行性

算法的基本语句执行次数和时间复杂度

简单的我觉得没有必要再看了,直接上例题来参悟

inti,j;
for(i=0;i<n; i++)
{
    for(j=i;j<n;j++) /*注意j一1而不是0 */
    {
        /*时间复杂度为0(1)的程序步骤序列*/
    }
}

由于当i=0时,内循环执行了n次,当i=1时,执行了n-1次~~~当i=n-1时,执行了1次。所以总的执行次数为:

时间复杂度为O(n2)

n++;                 /*执行次数为1 */
function (n) ;       /*执行次数为n*/
inti,j;
for(i=0;i<n;i++)/*执行次数为 n2*/
{
     function(i) ;
}
for(i=0;i<n; i++)/*执行次数为n(n+ 1)/2*/
{
    for(j=i;j<n;j++)
    {
        /*时间复杂度为0(1)的程序步骤序列*/
    }
}

例题:

  • 一个算法的时间复杂度为(3n3+2000n‎log2n‎+90)/n2,其数量级‎示为____‎。

O(n)

空间复杂度

n为问题的规模,f(n)为语句关于n所占存储空间的函数

线性表


例题:

  • 对线性表,在下列哪种情况下应当采用链表表示?( ) B

A.经常需要随机地存取元素 B.经常需要进行插入和删除操作

C.表中元素需要占据一片连续的存储空间 D.表中元素的个数不变

顺序存储结构


插入
StatusListInsert (SqList*L,inti,ElemTypee)
{
    intk;
    if (L->length==MAXSIZE) /*顺序线性表已经满*/
        returnERROR;
    if(i<1||i>L->length+1) /*当i不在范围内时*/
        returnERROR;
    if (i<=L->length) /*若插入数据位置不在表尾*/
    {
        for (k=L->length-1;k>=i-1;k--)/*将要插入位置后数据元素向后移动一位*/
            L->data[k+1]-L->data[k];
    }
    L->data[i-1]=e;治/*将新元素插入*/
    L->length++;
    returnOK;
}

从最后一个元素开始移,所以是length-1

直到插入位置原来对应的元素结束,所以中间是i-1,并且有等于

例题:

  • 对于一个长度为n的顺序存储的线性表,在表头插入元素的时间复杂度为__,在表尾插入元素的时间复杂度为‎_‎

O(n) O(1)

删除
StatusListDelete (SqList*L, inti,ElemType*e )
{
    intk;
    if (L->length==0)    /*线性表为空*/
        returnERROR;
    if (i<1||i>L->length) /*删除位置不正确*/
        returnERROR;
    *e=L->data[i-1];
    if (i<L->length )    /*如果删除不是最后位置*/
    {
        for (k=i;k<L->length;k++)/*将删除位置后继元素前移*/
            L->data[k-1]=L->data[k];
    }
    L->length--;
    returnOK;
}

假如删除的是第2个数据,由于计算机从0开始,正好将存储空间中2号位上的开始往前移,直到最后一个元素

所以k=i,表示第i个元素开始;所以k< L->length,没有=,因为此时这个位置没有数据

例题:

  • 编写从类型为List的线性表L中将第i个元素删除的算法,(假定不需要对i的值进‎行有效性检查,也不用判别L是否为空表。)

void Delete(List&L, inti)
      {
           for(int j=i-1;j<L.size-1; j++)
               L.list[j]=L.list[j+1];         
           L.size--;
       }

链式存储结构


例题:

  • 在如下数组A中链接存储了一个线性表,表头指针存放在A [ 0].next,试写出该线‎性表。

A 0 1 2 3 4 5 6 7

data

60

50

78

90

34

40

next

4

0

5

2

7

1

3

答: 线性表为:(90,40,78,50,34,60)

备注:这题没啥难的,难得就是,没想到会这么简单

  • 在下面的每个程序段中,假定线性表La的类型‎为List,元素类型ElemTy‎pe为in‎t,并假定每个程序段是连续执行的。试写出每个程序段执行后所得到的线性表La‎。

InitList(La);
Int a[]={100,26,57,34,79};
For (i=0;i<5;i++)
Insert(La,a[i]);
TraverseList(La);

DeleteFront(La);
InsertRear(La, DeleteFront(La));
TraverseList(La);

ClearList(La);
For (i=0;i<5;i++)
InsertFront(La,a[i]);
TraverseList(La);

(1) La=(26,34,57,79,100)

(2)La=(57,79,100,34)

(3)La=(79,34,57,26,100)

单链表

插入
Status ListInsert ( LinkList *L,int i, ElemType e)
{
    int j;
    LinkList P,s;
    P=*L;
   j=1;
    while (p && j<i)/*寻找第1个结点*/
    {
        p = p->next;
        ++j;
    }
    if (!p||5>1)
        returnERROR;/*第i个元素不存在*/
    s= (LinkList) malloc (sizeof (Node) ) ;/*生成新结点(C标准函数) */
    s->data=e;
    s->next=p->next:/*将p的后继结点赋值给s的后继*/
    p->next=s;/*将s赋值蛤p的后继*/
    return OK:
 }

例题:

  • 在一个单链表HL中,若要在当前由指针p指向的结点后面插入一个由q指向的结点,则执行如下( D )语句序列。(三套卷子都出现了!这道题,必考题)

A. p=q; p->next=q; B. p->next=q; q->next=p;

C. p->next=q->next; p=q; D. q->next=p->next; p->next=q;

先连接这个位置,再给这个位置值

  • 向单链表的末尾添加一个元素的算法

Void InsertRear(LNode*&HL,constElemType&item)
{
    LNode*newptr;
    newptr=newLNode;
    If (______________________)
    {
        cerr<<"Memory allocation failare!"<<endl;
        exit(1);
    }
    ______________________=item;
    newptr->next=NULL;
    if (HL==NULL)
      HL=________________________;
    else
    {
        LNode*P=HL;
        While (P->next!=NULL)
            ___________________;
        p->next=newptr;
    }
}
newpt‎r==NULL  newpt‎r->=data   newpt‎r    p=p->next
  • 对于一个长度为n的单链存储的线性表,在表头插入元素的时间复杂度为__‎___,在表尾插入元素的时间复杂度为 。

O(1) O(n)

删除
Status ListDelete ( LinkList*L, int1, ElemType*e)
{
    intj;
    LinkListP, q;
    p=*L;
    j=1;
    while (p->next&&j<i) /*遍历寻找第 i个元素*/
    {
        P=p->next;
        ++j;
    }
    if (! (p->next) || j>i)
        return ERROR:/*第1个元素不存在*/
    q=P->next; 
    p->next=q->next;/*将q的后继赋值给p的后继*/
    *e=q->data;/*将q结点中的数据给e*/
    free (q) ;/*让系统回收此结点,释放内存*/
    return OK:
}

例题:

  • HL是单链‎表的头指针,试写出删除头结点的算法。

答案:

ElemType DeleFront(LNode*&HL)
{
    if (HL==NULL){
        cerr<<"空表"<<endl;
    exit(1);
}
    LNode*p=HL;
    HL=HL->next;
    ElemType  temp=p->data;
    delete p;
    return temp;
} 

查找
Status GetElem ( LinkList L,int i, ElemType*e )
{
    int j;
    LinkList p; /*声明一结点p*/
    P=L->next;/*让p指向链表L的第一个结点*/
    j=1;/*j为计数器*/
    while (p %%j<i) /*p不为空或者计数器j还没有等于主时,循环继续*/
    {
        P=p->next;/*让p指向下一个结点*/
        ++j;
    }
    if(!p||j>1)
        return ERROR; /*第i个元素不存在*/
    *e=p->data;/*取第工个元素的数据*/
    return OK;
}

例题:

HL为单链‎表的表头指针,试写出在该单链表中查找具有给定的元素item的算法‎。

答案:

bool Find(LNode*HL, ElemType& item)
{
  LNode*p=HL;
  while   p
     if (p->data==item){
     return true;
       }
     else  p=p->next;
  return false;
}

双向链表

将单链表中,终端结点的指针端由空指针改为指向头节点。使整个单链表形成一个环。

插入

顺序不能错!!!!!!!!!!!

s->prior=P;/*把p赋值给s的前驱,如图中①*/
S->next=P->next;/*把p->next赋值给s的后继,如图中②*/
P->next->prior=s;/*把s赋值给p->next的前驱,如图中③*/
P->next=s;/*把s赋值给p的后继,如图中④*/

删除
p->prior->next=P>next;/*把p->next赋值給p->prior的后继,如图中①*/
p->next->prior=p->prior;/*把p->prior赋值给p->next的前驱,如图中②*/
free(p)                 /*释放节点*/


概念,特征


  • 栈是限定仅在表尾进行插入和删除操作的线性表。

  • 我们把允许插入和删除的一端称为栈顶(top)

  • 另-端称为栈底(bottom)

  • 后进先出的线性表

  • 进栈出栈变化形式

  • 举例来说,如果我们现在是有3个整型数字元素1.2、3依次进栈,会有哪些出栈次序呢?

  • 第一种: 1、2、3进,再3、2、1出。这是最简单的最好理解的一种,出栈次序为321。

  • 第二种: 1进,1出,2进,2出,3进,3出。也就是进一个就出一个,出栈次序为123。.

  • 第三种: 1进,2进,2出,1出,3进,3出。出栈次序为213.

  • 第四种: 1进,1出,2进,3进,3出,2出。出栈次序为132.

  • 第五种: 1进,2进,2出,3进,3出,1出。出栈次序为231。

例题:

  • 字符A、B、C依次进入‎一个栈,按出栈的先后顺序组成不同的字符串,至多可以组‎成( B )个不同的字符串?

A.14 B.5    C.6    D.8

  • 一个栈的输入序列为1 2 3,则下列序列中不可能是栈的输出序列的是( ) C

A. 2 3 1 B. 3 2 1

C. 3 1 2 D. 1 2 3

  • 当用长度为N的数组顺序存储一个栈时,假定用top==N表示栈空‎,则表示栈满的条件是_____‎。

top==0

(这里如果不理解,那就联想后面,全是从MAXSIZE-1开始的,就知道了)

插入


Status Push (SqStack*s, SElemTypee)
{
    if (s->top--MAXSIZE-1) /* 栈满. */
    {
        returnERROR:
    }
    S->top++;/*栈頂指针增加一*/
    S->data[S->top]=e;/* 将新插入元素赋值给栈顶空间 */
    returnOK;
}

链栈:

StatusPush ( Linkstack*S, SElemTypee )
{
    LinkStackPtrs= (LinkStackPtr ) malloe (sizeof (StackNode) ) ;
    s->data-e;
    s->next=s->top;/*把当前的栈顶元素赋值给新结点的直接后继,如图中①*/
    S->top=s;/*将新的结点s赋值给栈顶指针,如图中②*/
    S->count++:
    returnOK;
}

例题:

  • 向一个由HS指向的链栈中插入一个结点时p时,需要执行的操作是___;删除一个结点时,需要执行的操作是_‎_‎_‎_‎_(假设栈不空而且无需回收被删除结点)。

p->next=HS;HS=p HS=HS->next

删除


StatusPop (SqStack*s, SElemType*e)
{
    if (s->top == -1)
        returnERROR:
    *e=S->data[S->top];/*将要删除的栈顶元素赋值给e */
    S->top--;/*栈顶指针减一*/
    returnOK;
}

链栈

StatusPop (LinkStack*S,SElemType*e)
{
    LinkStackPtrP:
    if (StackEmpty(*S) )
        returnERROR;
    *e=S->top->data;
    p=S->top;/*将栈顶结点赋值给p.如图③*/
    s->top=S->top->next; /*使得栈頂指针下移一位,指向后一结点,如图④*/
    free(p) ;/*释放结点p */
    S->count--;
    returnOK;
}

队列


概念,特征


  • 只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

  • 先进先出的线性表

  • 允许插入的一端称为队尾,允许删除的一端称为队头

例题:

  • 以下数据结构中哪一个是线性结构‎?( B )

A. 有向图    B. 队列 C. 线索二叉树‎    D. B树

  • 以下哪一个不是队列的基本运算?( A)

A. 在队列第i个元素之后插入一个元素 B. 从队头删除一个元素

C. 判断一个队列是否为空‎ D.读取队头元素的值

  • 若顺序存储的循环队列的QueueMaxS‎ize=n,则该队列最多可存储( B )个元素.

A. n   B.n-1

C. n+1 D.不确定

  • 队列的插入操作是在队列的 ‎ 进行,删除操作是在队列的 进‎行。

尾 首

插入


链队

Status EnQueue ( LinkQueue*Q, QE1emTypee)
{
    QueuePtrs= ( QueuePtr ) malloc (sizeof (QNode) ) ;
    if( !s)/*存储分配失败*/
        exit ( OVERFLOW) ;
    s->data=e;
    s->next=NULL;
    Q->rear->next-s; /* 把拥有元素e新结点s赋值给原队尾结点的后继,见上图中①*/
    Q->rear=s;/*把当前的s设置为队尾结点,rear指向s,见上图中②*/
    return OK;
}

例题:

  • 对于一个长度为n的单链存储的队列,在表头插入元素的时间复杂度为__,在表尾插入元素的时间复杂度为‎__‎

O(1) O(1)

删除


链队

Status DeQueue ( LinkQueue*Q, QElemType*e)
{
    QueueptrP;
    if (Q->front==Q->rear )
        returnERROR:
    p=Q->front->next; /*将欲删除的队头结点暂存给p,见上图中①*/
    *e=p->data;/* 将欲删除的队头结点的值赋值给e */
    Q->front->next=p->next;  /*将原队头结点后继p->next赋值给头结点后继,见上图中②*/
    if (Q->rear==p) /*若队头是队尾, 则删除后将rear指向头结点,见上图中③*/
        Q->rear-Q->front;
    free(p) ;
    returnOK;
}


  • 由零个或多个字符组成的有限序列,又名字符串

  • 空串:零个字符的串

  • 空格串:只包含空格的串

数组和广义表


广义表:

  • 又称为列表

  • A = ():A 表示一个广义表,只不过表是空的。

  • B = (e):广义表 B 中只有一个原子 e。

  • C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d)。

  • D = (A,B,C):广义表 D 中存有 3 个子表,分别是A、B和C。这种表示方式等同于 D = ((),(e),(b,c,d)) 。

  • E = (a,E):广义表 E 中有两个元素,原子 a 和它本身。这是一个递归广义表,等同于:E = (a,(a,(a,…)))。

长度:广义表中所包含的数据元素的个数

  • 例如,在广义表 {a,{b,c,d}} 中,它包含一个原子和一个子表,因此该广义表的长度为 2。

  • 再比如,广义表 {{a,b,c}} 中只有一个子表 {a,b,c},因此它的长度为 1。

广义表的深度:通过观察该表中所包含括号的层数间接得到。比如:广义表 {{1,2},{3,{4,5}}} 中,子表 {1,2} 和 {3,{4,5}} 位于同层,此广义表中包含 3 层括号,因此深度为 3

  • 广义表A= (a,(a,b),((a,b),c)),则它的深度为__,它的长度为__‎__。

3 3

多维数组


例题:

  • 设W为一个二维数组,其每个数据元素占用4个字节,行下标i从0到7 ,列下标j从0到3 ,则二维数组W的数据元‎素共占用_‎个字节。W中第6 行的元素和‎第4 列的元素共占用___‎个字节。若按行顺序存放二维数组W,其起始地址为100,则二维数组元素W[6,3]的起始地址为___‎。

128 44 208(只要理解了定义,就是简单的小学加法而已)

特殊矩阵


稀疏矩阵的压缩思想


这是一个稀疏矩阵,若对其进行压缩存储,矩阵中各非 0 元素的存储状态如图 2 所示:

稀疏矩阵的压缩存储示意图存储的是三元组(即由 3 部分数据组成的集合)组中数据分别表示(行标,列标,元素值)。

例题:

  • 在稀疏矩阵的带行指针向量的链接存储中,每个单链表中的结点都具有相同的‎( )。A

A.行号 B.列号 C.元素值 D.非零元素个‎数

已知一个6*5稀疏矩阵如右所示,试:

(1) 写出它的三元组线性表;

(2) 给出三元组线性表的顺序存储表示‎。

答:(1) ((1,5,1),(3,2,-1),(4,5,-2),(5,1,5),(6,3,7))

(2)

6

5

5

1

5

1

3

2

-1

4

5

-2

5

1

5

6

3

7

备注:(行,列,数)

树和二叉树


例题:

  • 假定一棵树的广义表表示为A(D(E,G),H(I,J)),则树中所含的结点数为­­­­_‎个‎,树的深度为__,树的度为__‎___。

7 2 2

  • 在一棵高度为5的理想平衡树中,最少含有__个结点,最多含有__个结点。

16 31

解析:理想平衡树:在一棵二叉树中,除最后一层外,其余层都是满的。然后就是简单的小学加法

  • 在树中,一个结点的直接后继结点称为该结点的__‎。一个结点的直接前趋结点称为该结点的__‎。

孩子(或子)结点 双亲(或父)结点

  • 二叉树是指度为2的____‎树‎。一棵结点数为N的二叉树,其所有结点的度的总和是___。

有序 n-1

  • 若对一棵完全二叉树从0开始进行结点的编号,并按此编号把它顺序存储到一维数组A中,即编号为0的结点存储到A[0]中。其余类推,则A[ i ]元素的左孩子元素为_,右孩子元素为____,双亲元素为__‎__。

2i+1 2i+2 (i-1)/2

二叉树的存储结构


顺序存储结构

可以看作层序遍历

链式存储结构

二叉链表:

三叉链表:

例题:

试对图2中的二叉树画出其:

  • 顺序存储表示的示意图‎;

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

1

2

3

4

5

6

7

8

9

  • 二叉链表存储表示的示意图。

  • 对于一棵具有n个结点的二叉树,用二叉链表存储时,其指针总数为‎_‎个‎,其中__‎_‎个用于‎指向孩子,___‎__个指针‎是空闲的。

2n n-1 n+1

二叉树的五大性质


  • 在二叉树的第i层上至多有2^{i-1}个结点(i>1)。

  • 深度为k的二叉树至多有2^{k}-1个结点(k≥1)。

  • 对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1

  • 具有n个结点的完全二叉树的深度为[log2n]+1 ([x]表示不大于x的最大整数)。

  • 如果对一棵有 n个结点的完全二叉树的结点按层序编号,对任-结点i有:

  • 如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点[i/2」、

  • 如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i。

  • 如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。

例题:

  • 对于一棵具有n个结点的二叉树,一个结点的‎编号为i(1≤i≤n),若它有左孩‎子则左孩子结点的编号为__,若它有右孩子,则右孩子结点的编号为_‎_,若它有双亲,则双亲结点的编号为__‎__。

2i 2i+1 [i/2](或i/2)

A

二叉树


例题:

  • 下列关于二叉树遍历的叙述中,正确的是( ) 。D

A. 若一个树叶是某二叉树的中序遍历的最后一个结点,则它必是该二叉树的前序遍历最后一个结点

B.若一个点是某二叉树的前序遍历最后一个结点,则它必是该二叉树的中序遍历的最‎后一个结点‎

C.若一个结点是某二叉树的中序遍历的最后一个结点,则它必是该二叉树的前序最后一个结点

D.若一个树叶是某二叉树的前序最后一个结点,则它必是该二叉树的中序遍历最后一个结点

前序遍历

例题:

下面算法的功能是什么

void ABC(BTNode*BT)
{
        if  BT {
          cout<<BT->data<<' ';
          ABC(BT->left);
          ABC(BT->right);
          }
        } 

前序遍历链‎式存储的二‎叉树。

中序遍历

后序遍历

层次遍历

例题:

以下题基于图‎1

  • 该二叉树结点的前序遍历的序列为‎( C )。

A. E、G、F、A、C、D、B

B. E、A、G、C、F、B、D

C. E、A、C、B、D、G、F

D. E、G、A、C、D、F、B

  • 该二叉树结点的中序遍历的序列为‎( A )。

A. A、B、C、D、E、G、F

B. E、A、G、C、F、B、D

C. E、A、C、B、D、G、F

D. B、D、C、A、F、G、E

  • 该二叉树的按层遍历的序列为( C )。

A.E、G、F、A、C、D、B     B. E、A、C、B、D、G、F

C. E、A、G、C、F、B、D      D. E、G、A、C、D、F、B

  • 下面关于图的存储的叙述中正确的是( B )。

A.用邻接表法存储图,占用的存储空间大小只与图中边数有关,而与结点个数无关

B.用邻接表法存储图,占用的存储空间大小与图中边数和结点个数都有关

C. 用邻接矩阵法存储图,占用的存储空间大小与图中结点个数和边数都有关

D.用邻接矩阵法存储图,占用的存储空间大小只与图中边数有关,而与结点个数无关

  • 已知一棵二叉树的前序遍历的结果是ABKCDFGHI‎J, 中序遍历的结果是KBCDAFH‎IGJ, 试画出这棵二叉树。

哈夫曼树的构造方法

(A)给定了四个结点a,b,c,d,权值分别为7,5,2,4;

第一步如(B)所示,找出现有权值中最小的两个,2 和 4 ,相应的结点 c 和 d 构建一个新的二叉树,树根的权值为 2 + 4 = 6,同时将原有权值中的 2 和 4 删掉,将新的权值 6 加入;

进入(C),重复之前的步骤。

直到(D)中,所有的结点构建成了一个全新的二叉树,这就是哈夫曼树。

带权路径长度和的求解


上面那个中,它的带权路径长度和=7 * 1+5 * 2+2 * 3+4 * 3=35

它的值乘以距离相加

例题:

  • 由权值分别为3,8,6,2的叶子生‎成一棵哈夫曼树,它的带权路径长度为( B )。

A. 11 B.35 C. 19 D. 53

森林和二叉树,树和二叉树之间互相转换


树转二叉树

森林转二叉树

二叉树转化为树

二叉树转化为森林

二叉树的应用算法


二叉搜索树(二叉排序树)


在二叉搜索树中:

  • 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;

  • 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;

  • 任意节点的左、右子树也分别为二叉查找树;

  • 没有键值相等的节点。

例题:

  • 从二叉搜索树中查找一个元素时,其时间复杂度大致为( )。 C

A. O(n) B. O(1) C. O(log2n‎) D. O(n2)

  • 写出下列中缀表达式的后缀形式:

(1) 3X/(Y-2)+1

3X*Y2-/1+

(2) 2+X*(Y+3)

2XY3+*+

  • 对一棵二叉搜索树进行中序遍历时,得到的结点序列是一个__‎。对一棵由算术表达式组成的二叉语法树进行后‎序遍历得到‎的结点序列‎是该算术表‎达式的____

有序序列 后缀表达式‎(或逆波兰式‎)

  • 后缀算式79 2 30 + - 4 2 / *的值为___‎。中缀算式(3+X * Y)-2Y/3对应的后缀算式为‎‎_‎_‎_‎___‎。

94 3 X Y * + 2 Y * 3 / -

  1. 将操作数(数字)压入堆栈

  1. 当遇到操作符时,弹出栈顶的两个数,用该操作符将它们做相应的计算(栈顶元素 op 次顶元素),并将结果入栈

  1. 重复步骤 2,直到表达式最右边

  1. 将堆栈顶的值作为结果

对于后缀表达式 79 2 30 + - 4 2 / *,其计算顺序为:

  1. 将 79 和 2 压入堆栈;

  1. 将 30 压入堆栈;

  1. 将 + 运算符从堆栈中弹出,因此弹出 2 和 30(2 与 30 为前两个数,而 30 与 2 在堆栈中位置相邻,因此它们就是堆栈的前两个数),计算出 30+2 的值,即 32,并将 32 入栈;

  1. 将 79 和 32 压入堆栈;

  1. 将 - 运算符弹出,因此弹出 32 和 79,并将 79-32 的值 47 入栈;

  1. 将 4 和 2 压入堆栈;

  1. 将 / 运算符弹出,因此弹出 2 和 4,并将 4 ÷ 2 的值 2 入栈;

  1. 将 47 和 2 压入堆栈;

  1. 将 * 运算符弹出,因此弹出 2 和 47,并将 47 * 2 的结果 94 入栈;

  1. 将 94 入栈,即得到最终结

  • 设有一个输入数据的序列是 { 46, 25, 78, 62, 12, 80 }, 试画出从空树起,逐个输入各个数据而生成的二叉搜索树。


图的存储结构


例题:

  • 表示图的三种常用的存储结构___、_‎_‎‎_‎_‎_

邻接矩阵 邻接表 边集数组

  • 在一个具有10个顶点‎的无向完全图中,包含有__条边,在一个具有n个顶点的‎有向完全图中,包含有___‎条边。

45 n(n-1)

邻接矩阵

邻接表

无向图的邻接表

有向图的邻接表

例题:

对于图6所示的有向图若存储它采用邻接表,并且每个顶点邻接表中的边结点都是按照终点序号从小到大的次序链接的,试写出:

(1) 从顶点①出发进行深度优先搜索所得到的深度优先生成树;

(2) 从顶点②出发进行广度优先搜索所得到的广度优先生成树;

DFS:12345

BFS:23451

图的深度优先遍历算法


通俗的说,就是一条路走到黑,发现没路了,我就退,退,退,看看有没有被忽视的路。直到退到原点,结束

图的广度优先遍历算法


可以理解为图的”层序遍历“

譬如:

例题:

  • 写出下述算法的功能:

   void AJ(adjlist GL, int i, int n)
       {
           Queue Q;
           InitQueue(Q);
            cout<<i<<' ';
           visited[i]=true;
           QInsert(Q,i);
           while(!QueueEmpty(Q)) {
               int k=QDelete(Q);  
               edgenode* p=GL[k];  
               while(p!=NULL) 
               {
                   int j=p->adjvex;  
                   if(!visited[j]) 
                  {  
                       cout<<j<<' ';
                       visited[j]=true;
                       QInsert(Q,j);
                   }
                   p=p->next;  
               }
           }
       }

功能为:从初始点v‎i出发,广度‎优先搜索由‎邻接表GL‎所表示的图‎

构造最小代价生成树的方法


Prim算法

以某个顶点为起点,看下一步能走的路中哪个最小就走哪。

例题:

  • 已知一个图的顶点集V和边集E分别为:

V={1,2,3,4,5,6,7};

E={(1,2)3,(1,3)5,(1,4)8,(2,5)10,(2,3)6,(3,4)15,(3,5)12,(3,6)9,(4,6)4,

(4,7)20,(5,6)18,(6,7)25};

按照普里姆算法从顶点1出发得到‎最小生成树,试写出在最小生成树中依次得到的各条边。

  • 普里姆算法‎从顶点1出‎发得到最小‎生成树为:

(1,2)3, (1,3)5, (1,4)8, (4,6)4, (2,5)10, (4,7)20

Kruskal算法

把短的路径先都挑出来,n个端点,挑出n-1条线。然后再刚好连接所有的点

例题:

  • 已知一个图的顶点集V为:V={1,2,3,4,5,6,7};

其共有10条边。该图用如下边集数组存储:

起点

1

2

2

5

5

2

2

6

1

3

终点

6

4

5

4

7

6

7

7

7

5

1

1

2

2

2

3

3

4

5

7

试用克鲁斯卡尔算法依次求出该图的最小生成树中所得到的各条边及权值。

AOV网及拓扑顺序


这是一个AOV网,也就是有向无环图,写出它的拓扑顺序的方法:

  1. 从 AOV网中选择一个 没有前驱(即入度为0)的顶点并输出。

  1. 从图中删除该顶点和所有以它为起点的有向边。

  1. 重复 1 和 2 直到当前的 AOV网为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。

于是,得到拓扑排序后的结果是 { 1, 2, 4, 3, 5 }。

例题:

  • AOV网是一种( )。 D

A.有向图 B.无向图 C.无向无环图‎ D.有向无环图‎

  • 已知一个图的顶点集V和边集E分别为:

V={1,2,3,4,5,6,7};

E={<2,1>,<3,2>,<3,6>,<4,3>,<4,5>,<4,6>,<5,1>,<5,7>,<6,1>,<6,2>,<6,5>};

若存储它采用邻接表,并且每个顶点邻接表中的边结点都是按照终点序号从小到大的次序链接的,按主教材中介绍的拓朴排序算法进行排序,试给出得到的拓朴排序的序列。

答:拓朴排序为‎: 4 3 6 5 7 2 1

查找


折半(二分)查找

int Binary Search(int *a,int n,int key)
{
    int 1ow, high, mid;
    1ow=1;/*定义最低下标为记录首位*/
    high=n;/*定义最高下标为记录末位*/
    while ( low<=high )
    {
        mid= ( low+high) /2;    /*折半*/
        if (key<a [mid] )        /*若查找值比中值小*/    
            high- mid-1;        /*最高下标调整到中位下标小一位*/
        else if (key>a [mid])    /*若查找值比中值大*/
            low-mid+1:            /*最低下标调整到中位下标大一位*/
        else
            return mid;            /*若相等则说明mid即为查找到的位置*/
    }
    return 0;
}

例题:

  • 以二分查找方法从长度为10的有序表中查找一个元素时,平均查找长度为____‎。

2.9

  • 对线性表进行二分法查找,其前提条件是( ).C

A.线性表以链接方式存储,并且按关键码值排好序‎

B.线性表以顺序方式存储,并且按关键码值的检索频率排好序‎

C. 线性表以顺序方式存储,并且按关键码值排好序‎

线性表以链接方式存储,并且按关键码值的检索频率排好序

  • 二分查找的递归算法

Int Binsch(ElemType A[],int low,int high,KeyTy‎pe K)
        {
         if ______________
         {
            int mid=(low+high)/2;
            if (______) return mid;   //查找成功,返回元素的下标
            else if (K<A[mid].key)
               return Binsch(A,low,mid-1,K);             //在左子表上继续查找
            else return_________;     //在右子表上继续查找
          }
         else ______;              //查找失败,返回-1
        }

答案:(low<=high) K==A[mid].key Binsc‎h(A,mid+1,hight‎,K) retur‎n -1

  • 如下为二分查找的非递归算法,试将其填写完整

Int Binsch(ElemType A[ ],int n,KeyType K)
{
int low=0;
int high=n-1;
while (low<=high)
{
    int mid=______;
    if (K==A[mid].key)  return mid;      //查找成功,返回元素的下标
          else if (K<[mid].key) 
            _______;      //在左子表上继续查找
              else ________;      //在右子表上继续查找
}
return -1;      //查找失败,返回-1
}

答: (low+high)/2 high=mid-1 low=mid+1

二叉排序树


二叉排序树:

二叉排序树或者是一棵空树,或者是一棵具有下列特性的非空二叉树1) 若左子树非空,则左子树上所有结点关键字均小于根结点的关键字值;2) 若右子树非空,则右子树上所有结点关键字均大于根结点的关键字值;3) 左、右子树本身也分别是一棵二叉排序树。

对二叉排序树的查找

二叉排序树的查找是从根结点开始的,沿某个分支逐层向下进行比较的过程。 其查找过程描述如下:将给定值与根结点的关键字比较,若相等,则查找成功;若不等,则当根结点的关键字值大于给定关键字值时,在根结点的左子树中查找;否则在根结点的右子树中查找。

递归算法:
BSTNode *Search(BSTNode *root, int x){
    if(root->data == x){
        return root;
    }else if(x < root->data){
        return Search(root->left, x);
    }else{
        return Search(root->right, x);
    }
}
非递归算法
BSTNode *Search(BSTNode *root, int x){
    BSTNode *p = root;
    while(p!=NULL && p->data!=x){
        if(x < p->data)
            p = p->left;
        else
            p = p->right;
    }
    return p;
}

例题:

  • 在一棵m阶B树上,每个非树根结点的关键字数目最少为__个‎,最多为____‎个,其子树数目最少为__,最多为__

[m/2]-1 m-1 [m/2] m

哈希表的构造及冲突解决方法,哈希表的ASL的求解


  • 哈希表其实也叫散列表(记住啊!!!!!!!!!!书上都叫哈希表,卷子上都叫散列表)

  • 哈希表本质上,是数组,也就是线性表。既然是数组,那就是一排数据,每个数据有自己的位置。

例如:[100,20,21,35,3,78,99,10]

  • 譬如100,在这里称之为——关键字key。因为我们要把这些数,也就是关键字进行整理

  • 这个关键字key,很杂,没规律,不能直接拿来用,要把它变得整齐,这就需要一套规则,也就是哈希函数,关键字用哈希函数处理后,就是哈希值,或者叫哈希地址

  • 构造哈希函数的方法:(名字很直白,就不解释了,也没啥解释的)

  • 平方取中法

  • 除留取余法

  • 随机数法

  • 但这哈希函数往往不是万能的,总会出现,两个计算结果一摸一样,一样了,说明遇见哈希冲突了,解决哈希冲突的方法:(继续延用刚才的数组,哈希函数为,H(K)=k%7)

  • 开放地址法

算出来的哈希值,我往后移一下,直到有空位置

这就涉及到,总有一些数是要进行比较的,有些不用,所以就有了比较次数这一说

哈希地址

0

1

2

3

4

5

6

7

关键字

21

35

100

4

78

99

20

10

比较次数

1

2

1

1

4

5

1

5

平均查找长度=(4 * 1+1 * 2+1 * 4+ 2 * 5)/8=2.5

  • 链地址法

例题:

  • 对于线性表(70,34,55,23,65,41,20)进行散列存储时,若选用H(K)=K %7作为散列函数,则散列地址为0的元素有___个‎,散列地址为6的有___‎个。

1 4

  • 对于线性表(7,34,77,25,64,49,20,14)进行散列存储时,若选用H(K)=K%7作为散列‎函数,则散列地址为0的元素有( )个, D

A.1 B.2 C.3 D.4

  • 假定一个线性表为(12,17,74,5,63,49,82,36),若按Key% 4条件进行划分,使得同余数的素成为一个子表,则得到的四个子表分别为__‎_‎_‎____‎、____‎_‎_‎_‎_‎___‎。

(12,36) (17,5,49) (74,82) (63)

  • 在线性表的散列存储中,装填因子a又称为装填系数,若用m表示散列表的长度,n表示待散‎列存储的元素的个数,则a等于___‎。

n/m

备注:装填因子,就如其名,平均每条链装填了多少个关键字

  • 采用开放定址法处理散列表的冲突时,其平均查找长度( )。B

A.低于链接法处理冲突 B. 高于链接法处理冲突

C.与链接法处理冲突相同‎ D.高于二分查找

  • 在线性表的散列存储中,处理冲突的常用方法有________和‎‎_‎_‎_‎_‎__两‎种。

不需要我给答案了

排序

个人歪理:从第二张图,第二列开始记。

  • 插入排序,就是想扑克牌。你移动的数字,你不知道它是大是小

  • 选择排序,扩充句子——选择一个小的,或选择一个大的。你是知道它是最大的或是最小的

  • 交换排序,扩充句子——两个数字比完大小交换。

相当于我们对lowB三人组——插入排序,选择排序,冒泡排序有一个大致的印象。

然后,我们就可以背一下它们的时间空间复杂度,和稳定性。

下一步,看堆排序,奶奶的,哪套题都有堆排序!这道题,必考题。不考我倒立洗头

lowB 3人组


下面三个需要掌握算法,并且给出每趟排序结果

直接插入排序

void InsertSort(int a[],int l)
{
    int temp;
    int j;
    for(int i=1;i<l;i++)
    {
        if(a[i]<a[i-1])
        {
            temp=a[i];
            for(j=i-1;j>=0&&temp<a[j];j--)
            {
                a[j+1]=a[j];
            }
            a[j+1]=temp;

        }
        for(int k=0;k<l;k++)
            cout<<a[k]<<" ";
        cout<<endl;

    }
}

冒泡排序

void BubbleSort (sqList *L)
{
    int i,j;
    for ( i=1;i<L->1ength;i++ )
    {
        for (j=L->length-1;j>=i;j--) /* 注意是从后往前循环 */
        {
            if (L->r[j]>L->r[j+1]) /*若前者大于后者(注意这里与上一算法差异) */
            {
                swap (L,j,j+1);/*交换L->r[5]与L->r[j+1]的值*/
            }
        }
    }
}

简单选择排序

void InsertSort (SqList *L)
{
    int i,j;
    for (1-2;i<=L->length;i++)
    {
        if (L->r[i]<L->r[i-1])/*需将L->r[1]插入有序子表*/
        {
            L->r[0]=L->r[i];/*设置哨兵*/
            for (j=i-1;L->r[j]>L->r[0];j--)
                L->r[j+1]=L->r[j]; /* 记录后移*/
            L->r[j+1]=L->r[0];/*插入到正确位置*/
        }
    }
}

牛逼哄哄的排序


下面的排序理解即可,能给出每趟排序结果

例题:

  • 当待排序的记录数较大,排序码较随机且对稳定性不作要求时,宜采用___‎__排序‎;当待排序的记录数较大,存储空间允许且要求排序是稳定时,宜采用____‎__排序

快速 归并

Shell排序

1.假设现在有数组L,其中的数组元素为{0,5,9,7,8,3,6,2,1},让L[0]来存放中间变量。

2.第一趟循环后数组变为:

第一次为L[1]与L[5]的比较,0<8,不进行交换,第二次,5>3,进行交换,第三次,9>6,进行交换,第四次,7>2,进行交换,还有第五次,L[5]与L[9]的比较,8>1,进行交换。

3.第二趟循环后数组为:

第一次,L[1]与L[3]比较,0<6,不交换,第二次,3>2,交换,第三次,6>1,交换,第四次,2<5,不交换,第五次,6<9,不交换,第六次,5<7,不交换,第七次,9>8,交换。

4.第三趟循环后数组为:

第一次,L[1]与L[2]比较,0<2,不交换,第二次,2>1,交换,第三次,2<3,不交换,第四次,3<6,不交换...以此类推,最终得到数组:

快速排序

(50条消息) 快速排序法(详解)_李小白~的博客-CSDN博客_快速排序

例题:

  • 快速排序在最坏情况下的时间复杂度为( )。 D

A.O(log2n‎) B.O(nlog2‎n) C.0(n) D.0(n2)

堆排序

首先,我们来学习大根堆,小根堆就是反过来

首先我们给定一个无序的序列,将其看做一个堆结构,一个没有规则的二叉树,将序列里的值按照从上往下,从左到右依次填充到二叉树中。

那么如何构建呢? 我们找到了最后一个非叶子节点,即元素值为6的节点,比较它的左右节点中最大的一个的值,是否比他大,如果大就交换位置。

在这里5小于6,而9大于6,则交换6和9的位置

找到下一个非叶子节点4,用它和它的左右子节点进行比较,4大于3,而4小于9,交换4和9位置

此时发现4小于5和6这两个子节点,我们需要进行调整,左右节点5和6中,6大于5且6大于父节点4,因此交换4和6的位置

此时我们就构造出来一个大根堆,下来进行排序首先将顶点元素9与末尾元素4交换位置,此时末尾数字为最大值。排除已经确定的最大元素,将剩下元素重新构建大根堆

一次交换重构如图:

此时元素9已经有序,末尾元素则为4(每调整一次,调整后的尾部元素在下次调整重构时都不能动)

二次交换重构如图:

最终排序结果:

由此,我们可以归纳出堆排序算法的步骤:

1. 把无序数组构建成二叉堆。

2. 循环删除堆顶元素,移到集合尾部,调节堆产生新的堆顶。

例题:

  • 设有关键码序列(q,g,m,z,a,n,p,x,h),下面哪一个序列是从上述序列出发‎建堆的结果?( B )

A. a,g,h,m,n,p,q,x,z   B. a,g,m,h,q,n,p,x,z

C. g,m,q,a,n,p,x,h,z D. h,g,m,p,a,n,q,x,z

  • 当向一个大根堆插入一个具有最大值的元素时,需要逐层__调整,直到被调整到__‎___位置‎为止。

向上 根

  • 判断以下序列是否是小根堆? 如果不是, 将它调整为小根堆。

(1{ 12, 70, 33, 65, 24, 56, 48, 92, 86, 33 }

不是小根堆‎。调整为:{12,65,33,70,24,56,48,92,86,33}

(答案是这么给的,但反正我不是这个答案)

(2){ 05, 23, 20, 28, 40, 38, 29, 61, 35, 76, 47, 100 }

是小根堆

  • 对n个记录进行堆排序,所需要的辅助存储空间为 C

A. O(1og2n‎)   B. O(n)   C. O(1) D. O(n2)

  • 在堆排序的过程中,对任一分支结点进行筛运算的时间复杂度为__,整个堆排序过程的时间复杂度为__‎

O(log2n‎) O(nlog2‎n)

  • 画出向小根堆中加入数据4, 2, 5, 8, 3, 6, 10, 1时,每加入一个数据后堆的变化。

归并排序

例题:

在归并排序中,进行每趟归并的时间复杂度为__,整个排序过程的时间复杂度为___‎_‎,空间复杂度‎为__‎

O(n) O(nlog2‎n) O(n)

基数排序

现有如下序列:{3,44,38,5,47,15,36,32,50},现在要利用基数排序算法对这9个元素进行从小到大的排序,怎么排呢?首先,排序的初始化状态如图所示

第二,将这9个元素按个位分配到相应的位置上,如图所示

第三,将第二步分配好的结果按顺序取出,因为是按个位排序的,所以取出来的元素一定是按个位有序的,如图所示

第四,将元素按十位放入到相应的位置,上一步的数是按个位有序的,现在按十位放入相应的位置,放入之后,对于每个位置而言,都是大数在上面,小数在下面,如图所示

第五,因为是从小到大排序,将元素从左往右,从下到上依次取出,如图所示

算法设计与分析


  • 若需要利用形参直接访问实参时,应将形参变量说明为( )参数。D

A.值 B.函数 C.指针 D.引用

  • (1) 指出该算法的功能;

(2) 该算法的时间复杂度是多少?

1. int Prime(int n)

{

int i=1;

int x=(int) sqrt(n);

while(++i<=x)

if (n%i==0) break;

if (i>x) return 1;

else return 0;

}

答: (1) 判断n是否‎是素数(或质数)

(2)

递归算法


卷子上没有相关的题目,书上也就有一个汉诺塔问题,所以这里我什么也没写

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值