数据结构与算法复习笔记

news2024/12/27 12:25:56

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为基准的快速排序过程如下:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序禁止二次转发分享私密消息动态消息

第一种用法&#xff1a;私密消息 私密消息&#xff1a;运营人员分享小程序到个人或群之后&#xff0c;该消息只能在被分享者或被分享群内打开&#xff0c;不可以二次转发。 用途&#xff1a;主要用于不希望目标客群外的人员看到的分享信息&#xff0c;比如带有较高金额活动的…

【开源视频联动物联网平台】帧率、码率和分辨率

帧率、码率和分辨率是视频和图像处理中的重要概念&#xff0c;它们直接影响到视频的带宽占用和显示效果。在进行视频项目时&#xff0c;根据应用需求对视频参数进行调整是必要的&#xff0c;因此了解这些参数的具体含义和指标是非常重要的。 在进行视频项目时&#xff0c;需要…

软件系统安全漏洞检测应该怎么做?靠谱的软件安全检测公司推荐

软件系统安全漏洞检测是指通过对软件系统进行全面的、系统化的评估&#xff0c;发现和解决其中可能存在的安全漏洞和隐患。这些安全漏洞可能会被不法分子利用&#xff0c;引发数据泄露、系统瘫痪、信息被篡改等安全问题&#xff0c;给企业造成严重的经济和声誉损失。那么软件系…

万户ezOFFICE wpsservlet任意文件上传漏洞复现

0x01 产品简介 万户OA ezoffice是万户网络协同办公产品多年来一直将主要精力致力于中高端市场的一款OA协同办公软件产品&#xff0c;统一的基础管理平台&#xff0c;实现用户数据统一管理、权限统一分配、身份统一认证。统一规划门户网站群和协同办公平台&#xff0c;将外网信息…

【论文精读】HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face

HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in Hugging Face 前言Abstract1 Introduction2 Related Works3 HuggingGPT3.1 Task PlanningSpecification-based InstructionDemonstration-based Parsing 3.2 Model SelectionIn-context Task-model Assignment 3…

linux终端命令

comman [-options] [parameter] /主文件夹/视频 ls [-a -l -h] [Linux 路径] -a 全部文件显示 &#xff0c;因为有些是隐藏的文件 -l 以列表的形式展示内容&#xff0c;展示更加细节 -h 以易于阅读的形式&#xff0c;列出文件大小&#xff0c;如K、M、G 混合使用&#xff1a; l…

数据挖掘实战-基于word2vec的短文本情感分析(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

css新闻链接案例

利用html和css构建出新闻链接案例&#xff0c;使用渐变色做出背景色变化 background: linear-gradient(to bottom, rgb(137, 210, 251), rgb(238, 248, 254), white); 利用背景图片&#xff0c;调整位置完成 dd { height: 28px; line-height: 28px; background-image: url(./图…

网络周期间全球在线销售额飙升,提高排名是关键:7大策略速览

网络周期间&#xff08;11月23-27日&#xff09;&#xff0c;全球在线销售额增长6%&#xff0c;达到2980亿美元&#xff0c;其中美国销售额708亿美元&#xff0c;增长5%。增长主要由订单量推动&#xff0c;消费者需求首次增长&#xff0c;寻求低价和便利。人工智能支持的无缝和…

共享办公室平台和普通品牌之间存在哪些区别?三个角度告诉你答案

共享办公室平台是一种新兴的办公模式&#xff0c;它与传统的办公品牌有很多不同之处&#xff0c;主要可以从以下几个角度进行分析&#xff1a; 空间使用&#xff1a;共享办公室平台是一种基于共享经济理念的办公方式&#xff0c;它将空间、设施、服务等资源进行整合和优化&…

Unity中Shader编译目标渲染器

文章目录 前言一、Unity在打包时&#xff0c;会把Shader编译成不同平台对应的代码我们在状态栏&#xff0c;可以看见我们目前所处于的目标平台 二、在Unity中&#xff0c;怎么指定目标平台1、#pragma only_renderers2、#pragma exclude_renderers 三、我们测试一下看看效果1、 …

陈年雷司令葡萄酒中的石油笔记

雷司令葡萄酒通常在年轻时食用&#xff0c;当它们酿造出果味和芳香的葡萄酒时&#xff0c;可能带有绿色或其他苹果、葡萄柚、桃子、醋栗、蜂蜜、玫瑰花或切绿草的香气&#xff0c;并且由于酸度高&#xff0c;通常味道清脆。 雷司令天然的高酸度和各种风味使其适合长时间老化&am…

行测空间展开图类型题目通法

国考《行测》空间展开图类型题目通法 摘要 本文介绍一种判断哪一种立体图形可以由空间展开图组成的通用方法。 方法 1.将给定的展开图重构为容易识别的上边一个方块&#xff0c;下边一个方块&#xff0c;中间一个方块条的形式。 姑且称之为十字形吧。 之所以重构成这种形…

Windows核心编程 远程线程注入

目录 线程安全 C线程 C STL线程 远程线程注入概述 相关API CreateRemoteThread LoadLibrary VirtualAllocEx FreeLibrary GetProcAddress 远程线程注入 DLL卸载 调试DLL 线程安全 变量在单线程和在多线程都不会出问题 - 线程安全 变量在多线程出问题&#xff0c…

java编程:给定⼀组正整数数组M,找出M数组中N项和为给定数S。如果有多对N项数字的和都等于 S,则输出N个数的乘积最⼩的哪⼀项,没有则返回空

题目&#xff1a; 编程题&#xff1a;给定⼀组正整数数组M&#xff0c;找出M数组中N项和为给定数S。如果有多对N项数字的和都等于 S&#xff0c;则输出N个数的乘积最⼩的哪⼀项&#xff0c;没有则返回空&#xff1b; 程序如下&#xff1a; 测试主程序&#xff1a; 先看下测试示…

WordPress定时文章自动发布技巧

对于许多WordPress站长来说&#xff0c;文章的管理和发布计划往往是一个头疼的问题。随着内容的不断增加&#xff0c;时间表的调整以及发布频率的把握成为了让人焦头烂额的挑战。 一、时间管理难题 对于博客管理员来说&#xff0c;时间管理一直是个令人困扰的问题。在忙碌的生…

flutter开发实战-readmore长文本展开和收缩控件

flutter开发实战-readmore长文本展开和收缩控件 当长文本展开和收缩控件&#xff0c;我们需要使用readmore来处理长文本展开和收缩&#xff0c;方便阅读 一、引入readmore 在工程的pubspec.yaml中引入插件 readmore: ^2.1.0ReadMoreText的属性如下 const ReadMoreText(this.…

Python之Appium 2自动化测试(Android篇)

一、环境搭建及准备工作 1、Appium 2 环境搭建 请参考另一篇文章: Windows系统搭建Appium 2 和 Appium Inspector 环境 2、安装 Appium-Python-Client&#xff0c;版本要求3.0及以上 pip install Appium-Python-ClientVersion: 3.1.03、手机连接电脑&#xff0c;并在dos窗口…

云融未来,安全内在—第七届云安全联盟大中华区大会将于12月21日在深圳举办

第七届云安全联盟大中华区大会 将于12月21日在深圳举办 大会主题 “云融未来&#xff0c;安全内在” 大会内容 ↓ ​ 大会背景 自2016年起&#xff0c;云安全联盟大中华区大会已成功举办六届&#xff0c;享誉国际&#xff0c;搭建了国内外政府机构、企业代表、专家学者等各方…

网站监控有什么作用?

科技改变生活&#xff0c;科技的发展让我们的生活越来越精彩丰富&#xff0c;数据中心机房监控系统也可以称为“自我监控系统”&#xff0c;主要是针对机房所有的设备及环境进行集中监控和管理的&#xff0c;其监控对象构成机房的各个子系统&#xff1a;动力系统、环境系统、消…