数据结构与算法复习笔记

1.数据结构基本概念

数据结构: 它是研究计算机数据间关系,包括数据的逻辑结构和存储结构及其操作。
数据(Data):数据即信息的载体,是能够输入到计算机中并且能被计算机识别、存储和处理的符号总称。
数据元素(Data Element):数据元素是数据的基本单位,又称之为记录(Record)。一般,数据元素由若干基本项(或称字段、域、属性)组成。

数据结构
逻辑结构
存储结构
线性结构
线性表
队列
非线性结构
树形结构
图形结构
顺序存储
链式存储
索引存储
散列存储
数据运算
检索\排序\插入\删除\修改

1.1.数据的逻辑结构

数据的逻辑结构表示数据运算之间的抽象关系。按每个元素可能具有的直接前趋数和直接后继数将逻辑结构分为“线性结构”和“非线性结构”两大类。
线性结构:
在这里插入图片描述
一个对一个,如线性表、栈、队列
树形结构:
在这里插入图片描述
一个对多个,如树。

图状结构
在这里插入图片描述
多个对多个
此外还有集合
在这里插入图片描述
数据元素间除“同属于一个集合”外,无其它关系。

1.2.数据的存储结构

存储结构:逻辑结构在计算机中的具体实现方法。

存储结构是通过计算机语言所编制的程序来实现的,因而是依赖于具体的计算机语言的。

顺序存储(Sequential Storage):
将数据结构中各元素按照其逻辑顺序存放于存储器一片连续的存储空间中。
如c语言的一维数组,如表 L=(a1,a2,……,an)的顺序结构
在这里插入图片描述
在这里插入图片描述
链式存储(重点)
将数据结构中各元素分布到存储器的不同点,用地址(或链指针)方式建立它们之间的联系。
在这里插入图片描述
数据结构中元素之间的关系在计算机内部很大程度上是通过地址或指针来建立的。

索引存储
在存储数据的同时,建立一个附加的索引表,即索引存储结构=数据文件+索引表。
在这里插入图片描述
散列存储:
根据数据元素的特殊字段(称为关键字key),计算数据元素的存放地址,然后数据元素按地址存放
在这里插入图片描述

2.线性表

线性表是包含若干数据元素的一个线性序列
记为: L=(a0, … ai-1, ai, ai+1 … an-1)

L为表名,ai (0≤i≤n-1)为数据元素;
n为表长,n>0 时,线性表L为非空表,否则为空表。
线性表L可用二元组形式描述:

		L= (D,R)

即线性表L包含数据元素集合D和关系集合R

  D={ai | ai∈datatype ,i=0,1,2, ∙∙∙∙∙∙∙∙∙n-1 ,n≥0}
  R={<ai , ai+1> | ai , ai+1∈D, 0≤i≤n-2}
  • 关系符<ai, ai+1>在这里称为有序对
  • 表示任意相邻的两个元素之间的一种先后次序关系
  • ai是ai+1的直接前驱, ai+1是ai的直接后继

线性表的特征:

  1. 对非空表,a0是表头,无前驱;
  2. an-1是表尾,无后继;
  3. 其它的每个元素ai有且仅有一个直接前驱ai-1和一个直接后继ai+1。

线性表包括顺序表和链表,其中链表又包括单链和双链。线性表具体分类如下:
在这里插入图片描述
设有一个顺序表L={1,2,3,4,5,6}; 他们的关系如图:

1
2
3
4
5
6

使用二元组描述L=(D,R),则

		D={1 , 2 , 3 , 4 , 5 , 6}(n=6)
		R={<1,2> , <2,3> , <3,4> , <4,5> , <5,6>}

2.1. 顺序表

2.1.1.顺序存储结构的表示

若将线性表L=(a0,a1, ……,an-1)中的各元素依次存储于计算机一片连续的存储空间。
设Loc(ai)为ai的地址,Loc(a0)=b,每个元素占d个单元 则:Loc(ai)=b+i*d
在这里插入图片描述

2.1.2.顺序存储结构的特点

  • 逻辑上相邻的元素 ai, ai+1,其存储位置也是相邻的
  • 对数据元素ai的存取为随机存取或按地址存取
  • 存储密度高,存储密度D=(数据结构中元素所占存储空间)/(整个数据结构所占空间)
  • 顺序存储结构的不足:
    对表的插入和删除等运算的时间复杂度较差

2.1.3.顺序存储的C语言实现

在C语言中,可借助于一维数组类型来描述线性表的顺序存储结构:

#define  N 100       
typedef   int  data_t;
typedef  struct                     
{   data_t data[N]//表的存储空间
     int last;   
}   sqlist, *sqlink; 

在这里插入图片描述

2.1.4.线性表的基本运算

设线性表 L=(a0,a1, ……,an-1),对 L的基本运算有:
1)建立一个空表:list_create(L)
2)置空表:list_clear(L)
3)判断表是否为空:list_empty (L)。若表为空,返回值为1 , 否则返回 0
4)求表长:length (L)
5)取表中某个元素:GetList(L , i ), 即ai。要求0≤i≤length(L)-1
6)定位运算:Locate(L,x)。确定元素x在表L中的位置(或序号)

L o c a t e ( L , x ) = { i , 当元素 x = a i ∈ L , 且 a i 是第一个与 x 相等时 − 1 x 不属于 L 时 Locate(L,x) = \begin{cases} i , &当元素x=ai∈L,且ai是第一个与x相等时 \\ -1 & x不属于L时 \\ \end{cases} Locate(L,x)={i1当元素x=aiL,ai是第一个与x相等时x不属于L
定位:确定给定元素x在表L中第一次出现的位置(或序号)。即实现Locate(L,x)。算法对应的存储结构如图所示。
在这里插入图片描述
7)插入:
Insert(L,x,i)。将元素x插入到表L中第i个元素ai之前,且表长+1。
插入前: (a0,a1,—,ai-1,ai,ai+1-------,an-1) 0≤i≤n,i=n时,x插入表尾
插入后: (a0,a1,—,ai-1, x, ai,ai+1-------,an-1)

插入算法思路:若表存在空闲空间,且参数i满足:0≤i≤L->last+1,则可进行正常插入。插入前,将表中(L->data[L->last]~L->data[i])部分顺序下移一个位置,然后将x插入L->data[i]处即可。算法对应的表结构。
在这里插入图片描述
8)删除:
Delete(L,i)。删除表L中第i个元素ai,且表长减1, 要求0≤i≤n-1。
删除前: (a0,a1,—,ai-1,ai,ai+1-------,an-1)
删除后: (a0,a1,—,ai-1,ai+1-------,an)
删除:将表中第i个元素ai从表中删除,即实现DeleteSqlist(L, i)。
算法思路: 若参数i满足:0≤i≤L->last, 将表中L->data[i+1]∽L->data[L->last] 部分顺序向上移动一个位置,覆盖L->data[i]。
在这里插入图片描述

2.1.5.顺序表缺点

线性表的顺序存储结构有存储密度高及能够随机存取等优点,但存在以下不足:
(1)要求系统提供一片较大的连续存储空间。
(2)插入、删除等运算耗时,且存在元素在存储器中成片移动的现象;

2.2. 链表

链表主要学习单链表

2.2.1.线性表的链式存储结构:

将线性表L=(a0,a1,……,an-1)中各元素分布在存储器的不同存储块,称为结点,通过地址或指针建立元素之间的联系
在这里插入图片描述
结点的data域存放数据元素ai,而next域是一个指针,指向ai的直接后继ai+1所在的结点。
在这里插入图片描述

2.2.2.单链表的C语言实现

1.创建结构体

      typedef   struct  node
      {   data_t   data;   //结点的数据域//
           struct node *next;  //结点的后继指针域//
       }listnode, *linklist; 

在这里插入图片描述
设p指向链表中结点ai
在这里插入图片描述
获取ai,写作:p->data;
而取ai+1,写作:p->next->data
若指针p的值为NULL,则它不指向任何结点, 此时取p->data或p->next是错误的。
可调用C语言中malloc()函数向系统申请结点的存储空间

linklist  p; 
p = (linklist)malloc(sizeof(listnode));

则创建一个类型为linklist的结点,且该结点的地址已存入指针变量p中:
在这里插入图片描述
2.建立单链表
依次读入表L=(a0,…,an-1)中每一元素ai(假设为整型),若ai≠结束符(-1),则为ai创建一结点,然后插入表尾,最后返回链表的头结点指针H。
设L=(2,4,8,-1),则建表过程如下:
在这里插入图片描述
链表的结构是动态形成的,即算法运行前,表结构是不存在的
3.链表查找
1)按序号查找:实现GetLinklist(h, i)运算。
算法思路:从链表的a0起,判断是否为第i结点,若是则返回该结点的指针,否则查找下一结点,依次类推。
2)按值查找(定位) : 即实现Locate(h, x)。
算法思路:从链表结点a0起,依次判断某结点是否等于x,若是,则返回该结点的地址,若不是,则查找下一结点a1,依次类推。若表中不存在x,则返回NULL。
4.链表的插入
即实现InsertLinklist(h, x, i,)。将x插入表中结点ai之前的情况。
算法思路:调用算法GetLinklist(h, i-1),获取结点ai-1的指针p(ai 之前驱),然后申请一个q结点,存入x,并将其插入p指向的结点之后。
在这里插入图片描述
5.链表的删除
即实现DeleteLinklist(h, i), 算法对应的链表结构如图所示。
算法思路:同插入法,先调用函数GetLinklist(h, i-1),找到结点ai的前驱,然后将结点ai删除之。
在这里插入图片描述

2.2.3.设计算法,将单链表H倒置

算法思路:依次取原链表中各结点,将其作为新链表首结点插入H结点之后
在这里插入图片描述

2.2.4.设计算法,求两节点之和

设结点data域为整型,求链表中相邻两结点data值之和为最大的第一结点的指针。

算法思路:设p,q 分别为链表中相邻两结点指针,求p->data+q->data为最大的那一组值,返回其相应的指针p即可
在这里插入图片描述

2.2.5.链表合并

设两单链表A、B按data值(设为整型)递增有序,将表A和B合并成一表A,且表A也按data值递增有序。
算法思路:设指针p、q分别指向表A和B中的结点,若p->data ≤q->data则p结点进入结果表,否则q结点进入结果表。
在这里插入图片描述

3.栈

栈是限制在一端进行插入操作和删除操作的线性表(俗称堆栈),允许进行操作的一端称为“栈顶”,另一固定端称为“栈底”,当栈中没有元素时称为“空栈”。
特点 :后进先出(LIFO)。
在这里插入图片描述

3.1.顺序栈

它是顺序表的一种,具有顺序表同样的存储结构,由数组定义,配合用数组下标表示的栈顶指针top(相对指针)完成各种操作。

3.1.1.C语言实现

1.创建结构体

typedef  int  data_t ; /*定义栈中数据元素的数据类型*/
typedef struct 
{	
    data_t  *data ; 	/*用指针指向栈的存储空间*/
    int  maxlen;	/*当前栈的最大元素个数*/
    int  top ; 	/*指示栈顶位置(数组下标)的变量*/
  } sqstack; 		/*顺序栈类型定义*/

2.创建栈

sqstack *stack_create (int len)
{
sqstack *ss;
ss = (seqstack *)malloc(sizeof(sqstack));
ss->data = (data_t *)malloc(sizeof(data_t) * len);
ss->top = -1;
ss->maxlen = len;	
return ss;
}

在这里插入图片描述
3.清空栈

stack _clear(sqstack  *s)
{
	 s-> top = -1 ;
} 

//判断栈是否空 :
int  stack_empty (sqstack  *s)
{ 
	return   (s->top ==  -1  ?  1 : 0);
}

4.进栈

void  stack_push (sqstack  *s ,  data_t  x)
{	if (s->top = = N - 1{
	     printf ( “overflow !\n”) ; 
           return  ;
	}
	else  { 
		s->top ++  ;
		s->data[s->top] = x ;
	 }
	 return  ;
}

5.出栈

datatype  stack_pop(sqstack *s)
{
 s->top--;
	return  (s->data[s->top+1]);
}	

//取栈顶元素:
datatype  get_top(sqstack  *s)
{
      return (s->data[s->top]);
}

3.2.链式栈

C语言实现过程如下:
插入操作和删除操作均在链表头部进行,链表尾部就是栈底,栈顶指针就是头指针。
1.创建结构体

ypedef  int  data_t ;	 /*定义栈中数据元素数据类型*/
typedef  struct  node_t {
    data_t data ;		   /*数据域*/
	struct  node_t  *next ;   /*链接指针域*/
}  linkstack_t ; 		  /*链栈类型定义*/

在这里插入图片描述

2.创建空栈

 linkstack_t  *CreateLinkstack() { 
     linkstack_t  *top;
     top  =  (linkstack_t  *)malloc(sizeof(linkstack_t));
     top->next = NULL;
     return  top;  
}

//判断是否空栈 :
int  EmptyStack (linkstack_t *top)  
{	
	return  (top->next  == NULL  ?   1  :  0);
}

3.入栈

void   PushStack(linkstack_t *top,  data_t  x)
{	
linkstack_t  *p ;		
p = (linkstack_t *)malloc ( sizeof (linkstack_t) ) ; 
p->data = x ; 	
p->next = top->next;
top->next  =  p;   
return;	
}

4.队列

队列是限制在两端进行插入操作和删除操作的线性表

  • 允许进行存入操作的一端称为“队尾”
  • 允许进行删除操作的一端称为“队头”
  • 当线性表中没有元素时,称为“空队”
  • 特点 :先进先出(FIFO)
    在这里插入图片描述
    front指向队头元素的位置; rear指向队尾元素的下一个位置。
  • 在队列操作过程中,为了提高效率,以调整指针代替队列元素的移动,并将数组作为循环队列的操作空间。
  • 为区别空队和满队,满队元素个数比数组元素个数少一个。

4.1.顺序队列

C语言实现:
1.创建结构体

typedef  int  data_t ;    /*定义队列中数据元素的数据类型*/
#define  N  64	    /*定义队列的容量*/
typedef  struct {
      data_t  data[N] ;   /*用数组作为队列的储存空间*/
      int  front, rear ;     /*指示队头位置和队尾位置的指针*/
} sequeue_t ; 	     /*顺序队列类型定义*/

2.创建空队列

sequeue_t  *CreateQueue ()
{ 
      sequeue_t  *sq = (sequeue_t *)malloc(sizeof(sequeue_t));
      sq->front = sq->rear = maxsize -1;
      return  sq;
}
//判断队列空:
int   EmptyQueue (sequeue_t *sq)  {
      return (sq->front  = =  sq->rear) ;
}

3.入队
将新数据元素x插入到队列的尾部

void   EnQueue (sequeue_t *sq , data_t x)
{
	 sq->data[sq->rear] = x ; 
      sq->rear = (sq->rear + 1) % N ;	
       return ;
}

4.2.链式队列

在这里插入图片描述
在这里插入图片描述

C语言实现:
1.创建结构体
插入操作在队尾进行,删除操作在队头进行,由队头指针和队尾指针控制队列的操作。

typedef  int  data_t;     
typedef  struct  node_t
{   
	data_t data ;		
   struct node_t   *next; 	
 } linknode_t,  *linklist_t;                  
 typedef  struct
  {  
    linklist_t  front,  rear; 
  } linkqueue_t; 

2.创建空队列

linkqueue_t  *CreateQueue()
{ 
      linkqueue_t  *lq  =  (linkqueue_t  *)malloc(sizeof(linkqueue_t));
      lq->front = lq->rear = (linklist_t)malloc(sizeof(linknode_t));
      lq->front->next = NULL ;	  /*置空队*/
          return  lq;     /*返回队列指针*/
}

//判断队列空 :
int   EmptyQueue(linkqueue_t  *lq)  { 
   return ( lq->front  = =  lq->rear) ;
} 

3.入队


void  EnQueue (linkqueue_t *lq, data_t x)
{
    lq->rear->next (linklist_t)malloc(sizeof(linknode_t)) ; 
     lq->rear = lq->rear->next; 	     /*修改队尾指针*/
     lq->rear->data = x ;		     /*新数据存入新节点*/
	lq->rear->next = NULL ;	     /*新节点为队尾*/
    return;
}

4.出队

data_t  DeQueue(linkqueue_t  *lq)
{
    data_t   x;
	linklist_t   p;	       /*定义一个指向队头结点的辅助指针*/
	p = lq->front->next ;    /*将它指向队头结点*/
	lq->front->next = p->next ;     /*删除原先队头结点
     x = p->data;
	 free(p) ; 	/*释放原队头结点*/
    if  (lq->front->next  ==  NULL)  lq->rear  =  lq->front;
       return  x;
}

5.树和二叉树

5.1.树的相关概念

树(Tree)是n(n≥0)个节点的有限集合T,它满足两个条件 :

  • 有且仅有一个特定的称为根(Root)的节点。
  • 其余的节点可以分为m(m≥0)个互不相交的有限集合T1、T2、……、Tm,其中每一个集合又是一棵树,并称为其根的子树。
    表示方法 :树形表示法、目录表示法。
    在这里插入图片描述
    度: 一个节点的子树的个数称为该节点的度数,一棵树的度数是指该树中节点的最大度数。
  • 度数为零的节点称为树叶或终端节点
  • 度数不为零的节点称为分支节点
  • 除根节点外的分支节点称为内部节点。
    在这里插入图片描述
    路径: 一个节点系列k1,k2, ……,ki,ki+1, ……,kj,并满足ki是ki+1的父节点,就称为一条从k1到kj的路径
  • 路径的长度为j-1,即路径中的边数。
  • 路径中前面的节点是后面节点的祖先,后面节点是前面节点的子孙。
  • 节点的层数等于父节点的层数加一,根节点的层数定义为一。树中节点层数的最大值称为该树的高度或深度。
    在这里插入图片描述
    有序树: 若树中每个节点的各个子树的排列为从左到右,不能交换,即兄弟之间是有序的,则该树称为有序树。
    森林: m(m≥0)棵互不相交的树的集合称为森林。
    树去掉根节点就成为森林,森林加上一个新的根节点就成为树
    树的逻辑结构 :
    树中任何节点都可以有零个或多个直接后继节点(子节点),但至多只有一个直接前趋节点(父节点),根节点没有前趋节点,叶节点没有后继节点。

5.2.二叉树

二叉树是n(n≥0)个节点的有限集合,可以是空集(n=0)
也可以是由一个根节点以及两棵互不相交的、分别称为左子树和右子树的二叉树组成。
严格区分左孩子和右孩子,即使只有一个子节点也要区分左右。
在这里插入图片描述

5.2.1.二叉树的性质

二叉树第i(i≥1)层上的节点最多为2i-1个。
深度为k(k≥1)的二叉树最多有2k-1个节点。
满二叉树 : 深度为k(k≥1)时有2k-1个节点的二叉树。
完全二叉树 : 只有最下面两层有度数小于2的节点,且最下面一层的叶节点集中在最左边的若干位置上。
具有n个节点的完全二叉树的深度为
(log2n)+1或 log2(n+1)。
顺序存储结构 : 完全二叉树节点的编号方法是从上到下,从左到右,根节点为1号节点。设完全二叉树的节点数为n,某节点编号为i。

  • 当i>1(不是根节点)时,有父节点,其编号为i/2;
  • 当2i≤n时,有左孩子,其编号为2i ,否则没有左孩子,本身是叶节点;
  • 当2i+1≤n时,有右孩子,其编号为2i+1 ,否则没有右孩子;
  • 当i为奇数且不为1时,有左兄弟,其编号为i-1,否则没有左兄弟;
  • 当i为偶数且小于n时,有右兄弟,其编号为i+1,否则没有右兄弟;

有n个节点的完全二叉树可以用有n+1个元素的数组进行顺序存储,节点号和数组下标一一对应,下标为零的元素不用。
利用以上特性,可以从下标获得节点的逻辑关系。不完全二叉树通过添加虚节点构成完全二叉树,然后用数组存储,这要浪费一些存储空间。

5.2.2.二叉树的顺序存储

在这里插入图片描述

5.2.2.二叉树的链式存储

C语言实现创建结构体

typedef  int  data_t ;		
typedef  struct  node_t;		
{
	data_t data ; 		
	struct node_t *lchild ,*rchild ; 	
} bitree_t ; 			
bitree_t *root ; 	 

二叉树由根节点指针决定。
在这里插入图片描述

5.2.3.二叉树的遍历运算

遍历 : 沿某条搜索路径周游二叉树,对树中的每一个节点访问一次且仅访问一次。
二叉树是非线性结构,每个结点有两个后继,则存在如何遍历即按什么样的搜索路径进行遍历的问题。
由于二叉树的递归性质,遍历算法也是递归的。三种基本的遍历算法如下 :

  • 先访问树根,再访问左子树,最后访问右子树;
  • 先访问左子树,再访问树根,最后访问右子树;
  • 先访问左子树,再访问右子树,最后访问树根;

先序遍历算法

void  PREORDER ( bitree *r) 
{
    if ( r = = NULL ) return ;     //空树返回
    printf (%c ”,r->data );       //先访问当前结点
    PREORDER( r->lchild );     //再访问该结点的左子树
    PREORDER( r->rchild );     //最后访问该结点右子树
}

在这里插入图片描述
中序遍历算法
若二叉树为空树,则空操作;否则中序遍历左子树。
当访问根结点,中序遍历右子树。

void  INORDER ( bitree *r) 
{
    if ( r = = NULL ) return ;   //空树返回
    INORDER( r->lchild );     //先访问该结点的左子树
    printf (%c ”,r->data );    //再访问当前结点
    INORDER( r->rchild );     //最后访问该结点右子树
}

后序遍历算法
若二叉树为空树,则空操作;否则后序遍历左子树
当访问根结点,后序遍历右子树。

void  POSTORDER ( bitree *r) 
{
    if ( r = = NULL ) return ;     //空树返回
    POSTORDER( r->lchild );   //先访问该结点的左子树
    POSTORDER( r->rchild );  //再访问该结点右子树
    printf (%c ”,r->data );       //最后访问当前结点
}

遍历的路径相同,均为从根节点出发,逆时针沿二叉树的外缘移动,每个节点均经过三次。按不同的次序访问可得不同的访问系列,每个节点有它的逻辑前趋(父节点)和逻辑后继(子节点),也有它的遍历前趋和遍历后继(要指明遍历方式)。

按编号遍历算法 :

NOORDER  ( bitree *r) 		/*按编号顺序遍历算法*/
{
  int  front,  rear;
  bitree  *Q[N];
  if ( r == NULL ) return ; 		/*空树返回*/
  for (rear=1;rear<N; rear++) Q[rear] = NULL ;
  front = rear = 1;  Q[rear] = r;
  while ( Q[front] != NULL ) {	/*以下部分算法由学生完成设计*/
	
    /*访问当前出队节点*/
	
    /*若左孩子存在则左孩子入队*/
		
    /*若有孩子存在则右孩子入队*/
    
    /* front向后移动*/
    }  
}
#
#
#
#
A
B
C
D
E
F
G
H
I
J
K

6.查找算法

查找:
设记录表L=(R1 R2……Rn),其中Ri(l≤i≤n)为记录,对给定的某个值k,在表L中确定key=k的记录的过程,称为查找。
若表L中存在一个记录Ri的key=k,记为Ri.key=k,则查找成功,返回该记录在表L中的序号i(或Ri 的地址),否则(查找失败)返回0(或空地址Null)。

6.1.平均查找长度

对查找算法,主要分析其T(n)。查找过程是key的比较过程,时间主要耗费在各记录的key与给定k值的比较上。比较次数越多,算法效率越差(即T(n)量级越高),故用“比较次数”刻画算法的T(n)。

一般以“平均查找长度”来衡量T(n)。
平均查找长度ASL(Average Search Length):对给定k,查找表L中记录比较次数的期望值(或平均值),即:
在这里插入图片描述
Pi为查找Ri的概率。等概率情况下Pi=1/n;Ci为查找Ri时key的比较次数(或查找次数)。

6.2.顺序表的查找

顺序表,是将表中记录(R1 R2……Rn)按其序号存储于一维数组空间
记录Ri的类型描述如下:

typedef struct
{ 
 keytype key;    //记录key//
	     ……   //记录其他项//
} Retype;

顺序表类型描述如下:

#define maxn 1024     //表最大长度//
typedef struct 
{   
	Retype data[maxn];  //顺序表空间//
 	int len;   //当前表长,表空时len=0//
} sqlist;

若说明:sqlist r,则(r.data[1],……,r.data[r.len])为记录表(R1……Rn), Ri.key为r.data[i].key, r.data[0]称为监视哨,为算法设计方便所设。

算法思路: 设给定值为k,在表(R1 R2……Rn)中,从Rn开始,查找key=k的记录。

int sqsearch(sqlist r, keytype k)  
{   
	int i;
    r.data[0].key = k;  //k存入监视哨//
	i = r.len;  //取表长//
	while(r.data[i].key != k) i--;  
	return (i);
}

设Ci(1≤i≤n)为查找第i记录的key比较次数(或查找次数):

		若r.data[n].key = k,       Cn=1;
		若r.data[n-1].key = k,     Cn-1=2;
       		    ……
		若r.data[i].key = k,        Ci=n-i+1;
       		    ……
		若r.data[1].key = k,        C1=n

故ASL = O(n)。而查找失败时,查找次数等于n+l,同样为O(n)。

  • 对查找算法,若ASL=O(n),则效率是很低的,意味着查找某记录几乎要扫描整个表,当表长n很大时,会令人无法忍受。

6.3.折半查找算法

算法思路:
对给定值k,逐步确定待查记录所在区间,每次将搜索空间减少一半(折半),直到查找成功或失败为止。
设两个游标low、high,分别指向当前待查找表的上界(表头)和下界(表尾)。mid指向中间元素。
在这里插入图片描述
现查找k=20的记录。
再看查找失败的情况,设要查找k=85的记录。
在这里插入图片描述
C语言实现如下:

int Binsearch(sqlist r, keytype k)    //对有序表r折半查找的算法//
{  
	int low, high, mid;  low = 1;high = r.len; 
	while (low <= high)    
	{  
		mid = (low+high) / 2;   
        if (k == r.data[mid].key)  
        	return (mid);  
        if (k < r.data[mid].key) 
        	high = mid-1;  
        else 
        	low = mid+1;
	}      
     return(0);
 }     

不失一般性,设表长n=2h-l,h=log2(n+1)。记录数n恰为一棵h层的满二叉树的结点数。得出表的判定树及各记录的查找次数如图所示。
在这里插入图片描述

6.4.分块查找算法

设记录表长为n,将表的n个记录分成b=[n/s]个块,每块s个记录(最后一块记录数可以少于s个),即:
在这里插入图片描述
且表分块有序,即第i(1≤i≤b-1)块所有记录的key小于第i+1块中记录的key,但块内记录可以无序。
步骤:

  • 建立索引
  • 每块对应一索引项:
  • 其中kmax为该块内记录的最大key;link为该块第一记录的序号(或指针)。
    在这里插入图片描述
    在这里插入图片描述
  • 顺序、折半、分块查找和树表的查找中,其ASL的量级在O(n)~O(log2n)之间。
  • 不论ASL在哪个量级,都与记录长度n有关。随着n的扩大,算法的效率会越来越低。
  • ASL与n有关是因为记录在存储器中的存放是随机的,或者说记录的key与记录的存放地址无关,因而查找只能建立在key的“比较”基础上。

7.排序算法

稳定排序和非稳定排序
设文件f=(R1……Ri……Rj……Rn)中记录Ri、Rj(i≠j,i、j=1……n)的key相等,即Ki=Kj。
若在排序前Ri领先于Rj,排序后Ri仍领先于Rj,则称这种排序是稳定的,其含义是它没有破坏原本已有序的次序。
内排序和外排序

  • 若待排文件f在计算机的内存储器中,且排序过程也在内存中进行,称这种排序为内排序。
  • 若排序中的文件存入外存储器,排序过程借助于内外存数据交换(或归并)来完成,则称这种排序为外排序。
    各种内排序方法可归纳为以下五类:
    (1)插入排序
    (2)交换排序
    (3)选择排序
    (4)归并排序
    插入排序方法可归纳为以下五类:
    (1) 直接插入排序
    (2) 折半插入排序
    (3) 链表插入排序
    (4) Shell(希尔)排序

7.1.直接插入排序

设待排文件f=(R1 R2……Rn)相应的key集合为k={k1 k2……kn},
排序方法:
先将文件中的(R1)看成只含一个记录的有序子文件,然后从R2起,逐个将R2至Rn按key插入到当前有序子文件中,最后得到一个有序的文件。插入的过程上是一个key的比较过程,即每插入一个记录时,将其key与当前有序子表中的key进行比较,找到待插入记录的位置后,将其插入即可。
设文件记录的key集合k={50,36,66,76,95,12,25,36}
在这里插入图片描述

7.2.折半插入排序

排序算法的T(n)=O(n2),是内排序时耗最高的时间复杂度。

折半插入排序方法
先将(R[1])看成一个子文件,然后依次插入R[2]……R[n]。但在插入R[i]时,子表[R[1]……R[i-1]]已是有序的,查找R[i]在子表中的位置可按折半查找方法进行,从而降低key的比较次数。
在这里插入图片描述

7.3.链表插入排序

设待排序文件f=(R1 R2……Rn),对应的存储结构为单链表结构
在这里插入图片描述
链表插入排序实际上是一个对链表遍历的过程。先将表置为空表,然后依次扫描链表中每个结点,设其指针为p,搜索到p结点在当前子表的适当位置,将其插入。
设含4个记录的链表如图:
在这里插入图片描述

7.4.起泡排序

在这里插入图片描述

7.5.快速排序

设记录的key集合k={50,36,66,76,36,12,25,95},每次以集合中第一个key为基准的快速排序过程如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/204426.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python+pytest接口自动化(5)-requests发送post请求

简介 在HTTP协议中&#xff0c;与get请求把请求参数直接放在url中不同&#xff0c;post请求的请求数据需通过消息主体(request body)中传递。 且协议中并没有规定post请求的请求数据必须使用什么样的编码方式&#xff0c;所以其请求数据可以有不同的编码方式&#xff0c;服务…

watch监听中重复触发如何解决?

在实际开发工程中通过获取后端数据监听判断数组中长度是否大于0从而调用其他的方法&#xff0c;但是如果data域中的数据出现变化的话&#xff0c;就会导致监听中的方法重复调用&#xff0c;导致一些不必要的bug&#xff0c;例如&#xff1a; 原理&#xff1a; watch监听的数据…

在java java.util.Date 已知逝去时间怎么求年月日 数学计算不用其他方法

在Java中&#xff0c;使用java.util.Date类已知逝去时间求年月日的方法如下&#xff1a; 首先&#xff0c;获取当前时间和逝去时间之间的毫秒数差值&#xff0c;可以使用Date类的getTime()方法获得时间戳。 将毫秒数转换为秒数&#xff0c;并计算出总共的天数。 根据总共的天…

【刷题笔记】两数之和II_二分法||二分查找||边界||符合思维方式

两数之和II_二分法||二分查找 1 题目描述 https://leetcode.cn/problems/two-sum-ii-input-array-is-sorted/ 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设…

天眼销:超有用的企业获客工具

天眼销是资深数据团队开发的一个客户资源查询平台&#xff0c;可以通过多重筛选&#xff1a;企业名称/信用代码&#xff0c;所在地区&#xff0c;行业&#xff0c;注册资本&#xff0c;年限&#xff0c;是否在营/有电话/邮箱等。 天眼销和某查查有什么区别&#xff1f; 天*查/…

鸿蒙(HarmonyOS)应用开发——应用程序入口UIAbility

概述 UIAbility是一种包含用户界面的应用组件&#xff0c;主要用于和用户进行交互 UIAbility是系统调度的单元&#xff0c;为应用提供窗口在其中绘制界面 应用程序的几种交互界面形式 点击桌面图标进入应用 一个应用拉起另一个应用 最近任务列表切回应用 每一个UI Abili…

含压缩空气储能的零排放综合能源系统优化调度程序代码!

本程序参考SCI期刊论文《Optimal dispatch of zero-carbon-emission micro Energy Internet integrated with non-supplementary fired compressed air energy storage system》&#xff0c;程序中有详细的热网模型&#xff0c;温度控制模块&#xff0c;压缩机模块&#xff0c;…

二、shell编程快速入门

目录 1、入门示例 2、解释器 3、shell脚本执行方式 3.1 方式一&#xff1a;sh执行脚本 3.2 方式二&#xff1a;工作目录执行 3.3 方式三&#xff1a;绝对路径执行 ​​​​​​​4、shell的数据类型 4.1 字符串 4.2 整数型 1、入门示例 以下所有操作都在/export/shel…

Web应用渗透测试完全指南(二)

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

【开源】基于JAVA的天然气工程运维系统

项目编号&#xff1a; S 022 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S022&#xff0c;文末获取源码。} 项目编号&#xff1a;S022&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统角色分类2.2 核心功能2.2.1 流程…

lxd提权

lxd/lxc提权 漏洞介绍 lxd是一个root进程&#xff0c;它可以负责执行任意用户的lxd&#xff0c;unix套接字写入访问操作。而且在一些情况下&#xff0c;lxd不会调用它的用户权限进行检查和匹配 原理可以理解为用用户创建一个容器&#xff0c;再用容器挂载宿主机磁盘&#xf…

数据库安全运维系统厂家在深圳的有哪些?咨询电话多少?

IT小伙伴都知道&#xff0c;数据库安全运维至关重要&#xff0c;因为随着信息技术的不断发展&#xff0c;数据库已经成为企业存储、管理和处理数据的关键平台&#xff0c;数据库承载着企业不少数据资产。因此使用数据库安全运维系统是必要的。那你知道数据库安全运维系统厂家在…

Vue3 刷新后,pinia存储的数据丢失怎么解决

这个问题有两种解决办法&#xff1a; 一是使用pinia的持久化存储一是使用vue的依赖注入 刷新后&#xff0c;通过pinia存储的vue store数据丢失&#xff0c;实际上是因为Vue原组件卸载、新组件重新挂载导致的&#xff0c;vue store是挂载在组件上的&#xff0c;当刷新导致组件…

数据库的多表查询(MYSQL)表表联立

根据以上三张表格&#xff0c;对三张表格进行不同的联立&#xff0c;查询并显示符合条件的内容。 1. 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数。 mysql> SELECT d.deptno AS 部门编号, d.dname as 部门名称, d.loc as 部门位置, COUNT(e.emp…

uniapp2023年微信小程序头像+昵称分别获取

1、DOM <view class"m-user"><view class"user-info"><!--头像 GO--><button class"avatar avatar-wrapper" open-type"chooseAvatar" chooseavatar"onChooseAvatar"slot"right"><im…

2023-11-30 AIGC-让图片动起来的主流 AI 工具

摘要&#xff1a; 2023-11-30 AIGC-让图片动起来的主流 AI 工具 让图片动起来的主流 AI 工具 一、数字人播报 1、HeyGen 2、D-ID 3、SadTalker 二、图片生成视频 1、Runway Gen-2 2、Pika Labs 3、Genmo 三、伪3D动态效果 1、LeiaPix 2、剪映手机版 四、角色动画 Animated …

Sectigo代码签名证书——最优惠的解决方案

在软件开发领域&#xff0c;代码签名证书是确保软件安全和完整性的重要工具。它为开发者提供了一种验证其软件来源和内容的方式&#xff0c;同时向用户传递了信任和可靠性的信息。然而&#xff0c;高昂的代码签名证书费用一直是许多开发者面临的挑战之一。而Sectigo代码签名证书…

【漏洞复现】万户协同办公平台ezoffice SendFileCheckTemplateEdit.jsp接口存在SQL注入漏洞 附POC

漏洞描述 万户ezOFFICE协同管理平台是一个综合信息基础应用平台。 万户协同办公平台ezoffice SendFileCheckTemplateEdit.jsp接口存在SQL注入漏洞。 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害…

智能客服核心技术——预测会话与答案生成

1.信息检索 2. 句型模板匹配标准问题生成答案 3.根据知识图谱推理得到答案

【目标检测】进行实时检测计数时,在摄像头窗口显示实时计数个数

这里我是用我本地训练的基于yolov8环境的竹签计数模型&#xff0c;在打开摄像头窗口增加了实时计数显示的代码&#xff0c;可以直接运行&#xff0c;大家可以根据此代码进行修改&#xff0c;其底层原理时将检测出来的目标的个数显示了出来。 该项目链接&#xff1a;【目标检测…