数据结构小结

本小结仅仅只为考试,请为了学习的小伙伴不要太过参考。

数据结构讲了什么?

1.    什么是数据结构。

2.    链表

3.    队列和栈

4.   

a.    二叉树

b.    平衡二叉树

c.     B+

d.    B-

 

二叉树遍历先序、后序、中序遍历。

 

满二叉树

所有的分支结点都存在左子树和右子树,并且所有的叶子结点都在同一层上,这样就是满二叉树。就是完美圆满的意思,关键在于树的平衡。

根据满二叉树的定义,得到其特点为:

  1. 叶子只能出现在最下一层。
  2. 非叶子结点度一定是2.
  3. 在同样深度的二叉树中,满二叉树的结点个数最多,叶子树最多。

3、完全二叉树

对一棵具有n个结点的二叉树按层序排号,如果编号为i的结点与同样深度的满二叉树编号为i结点在二叉树中位置完全相同,就是完全二叉树。满二叉树必须是完全二叉树,反过来不一定成立。

其中关键点是按层序编号,然后对应查找。

B

       即二叉搜索树:

       1.所有非叶子结点至多拥有两个儿子(LeftRight);

       2.所有结点存储一个关键字;

       3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;

       如:

       

       B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;

否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入

右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字;

       如果B树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B

的搜索性能逼近二分查找;但它比连续内存空间的二分查找的优点是,改变B树结构

(插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销;

       如:

      

   但B树在经过多次插入与删除后,有可能导致不同的结构:

   右边也是一个B树,但它的搜索性能已经是线性的了;同样的关键字集合有可能导致不同的

树结构索引;所以,使用B树还要考虑尽可能让B树保持左图的结构,和避免右图的结构,也就

是所谓的“平衡”问题;      

       实际使用的B树都是在原B树的基础上加上平衡算法,即“平衡二叉树”;如何保持B

结点分布均匀的平衡算法是平衡二叉树的关键;平衡算法是一种在B树中插入和删除结点的

策略;

 

 

B-

       是一种多路搜索树(并不是二叉的):

       1.定义任意非叶子结点最多只有M个儿子;且M>2

       2.根结点的儿子数为[2, M]

       3.除根结点以外的非叶子结点的儿子数为[M/2, M]

       4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)

       5.非叶子结点的关键字个数=指向儿子的指针个数-1

       6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1]

       7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]

子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;

       8.所有叶子结点位于同一层;

       如:(M=3

       B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果

命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为

空,或已经是叶子结点;

B-树的特性:

       1.关键字集合分布在整颗树中;

       2.任何一个关键字出现且只出现在一个结点中;

       3.搜索有可能在非叶子结点结束;

       4.其搜索性能等价于在关键字全集内做一次二分查找;

       5.自动层次控制;

       由于限制了除根结点以外的非叶子结点,至少含有M/2个儿子,确保了结点的至少

利用率,其最底搜索性能为:

    

       其中,M为设定的非叶子结点最多子树个数,N为关键字总数;

       所以B-树的性能总是等价于二分查找(与M值无关),也就没有B树平衡的问题;

       由于M/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占

M/2的结点;删除结点时,需将两个不足M/2的兄弟结点合并;

 

 

B+

       B+树是B-树的变体,也是一种多路搜索树:

       1.其定义基本与B-树同,除了:

       2.非叶子结点的子树指针与关键字个数相同;

       3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树

B-树是开区间);

       5.为所有叶子结点增加一个链指针;

       6.所有关键字都在叶子结点出现;

       如:(M=3

   B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在

非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;

       B+的特性:

       1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好

是有序的;

       2.不可能在非叶子结点命中;

       3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储

(关键字)数据的数据层;

       4.更适合文件索引系统;

  


 

根据数据元素间关系的不同特性,通常有下列四类基本的结构:⑴集合结构。该结构的数据元素间的关系是属于同一个集合⑵线性结构。该结构的数据元素之间存在着一对一的关系。⑶树型结构。该结构的数据元素之间存在着一对多的关系。⑷图形结构。该结构的数据元素之间存在着多对多的关系,也称网状结构。

 

 

常用数据结构:

数组

在程序设计中,为了处理方便,把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称为数组。在C语言中,数组属于构造数据类型。一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。

是只能在某一端插入和删除的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。

队列

一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列是按照先进先出后进后出的原则组织数据的。队列中没有元素时,称为空队列。

链表

是一种物理存储单元上非连续、非顺序的存储结构,它既可以表示线性结构,也可以用于表示非线性结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

是包含nn>0)个结点的有穷集合K,且在K中定义了一个关系NN满足以下条件:

1)有且仅有一个结点 K0,他对于关系N来说没有前驱,称K0为树的根结点。简称为根(root)。 

2)除K0外,K中的每个结点,对于关系N来说有且仅有一个前驱。

3K中各结点,对关系N来说可以有m个后继(m>=0)。

图是由结点的有穷集合V和边的集合E组成。其中,为了与树形结构加以区别,在图结构中常常将结点称为顶点,边是顶点的有序偶对,若两个顶点之间存在一条边,就表示这两个顶点具有相邻关系。

在计算机科学中,堆是一种特殊的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。

队列、栈有很多模板,在STL中就可以找到。

List

栈的简单实现:

#include<iostream>

#include<stdlib.h>

using namespace std;

 

#define MAXSIZE 0xffff

 

template<classtype>

class my_stack

{

   int top;

   type*my_s;

   int maxsize;

 

public:

   my_stack():top(-1),maxsize(MAXSIZE)

   {

       my_s=newtype[maxsize];

       if(my_s==NULL)

       {

            cerr<<"动态存储分配失败!"<<endl;

            exit(1);

       }

   }

   my_stack(int size):top(-1),maxsize(size)

   {

       my_s=newtype[maxsize];

       if(my_s==NULL)

       {

            cerr<<"动态存储分配失败!"<<endl;

            exit(1);

       }

   }

   ~my_stack()

   {

       delete[] my_s;

   }

   //是否为空

   bool Empty();

   //压栈

   void Push(typetp);

    //返回栈顶元素

   typeTop();

   //出栈

   void Pop();

   //栈大小

   int Size();

};

 

template<classtype>

bool my_stack<type>::Empty()

{

   if(top==-1){

       returntrue;

   }

   else

       returnfalse;

}

 

template<classtype>

typemy_stack<type>::Top()

{

   if(top!=-1)

   {

       return my_s[top];

   }

   else

   {

       cout<<"栈空\n";

       exit(1);

   }

}

 

template<classtype>

void my_stack<type>::Push(typetp)

{

   if(top+1<maxsize)

   {

       my_s[++top]=tp;

   }

   else

   {

       cout<<"栈满\n";

       exit(1);

   }

}

 

template<classtype>

void my_stack<type>::Pop()

{

   if(top>=0)

   {

       top--;

   }

   else

   {

       cout<<"栈空\n";

       exit(1);

   }

}

 

template<classtype>

int my_stack<type>::Size()

{

   return top+1;

}

 

队列实现:

/* 顺序队列接口定义头文件*/

#define true 1

#define false 0

 

 

/* 队的最大长度 */

#define MAX_QUEUE_SIZE 100

/* 队列的数据类型 */

typedefint datatype;

 

/* 静态链的数据结构 */

typedefstructqueue{

   datatype sp_queue_array[MAX_QUEUE_SIZE];

   /*队头 */

   int front;

   /*队尾 */

   int rear;

}sp_queue;

 

 

/* 静态顺序链的接口定义 */

 

 

/* 静态链的初始化 */

sp_queue queue_init();

 

/* 判断队列是否为空,若为空

 *返回true

 *否则返回false

*/

int queue_empty(sp_queue q);

 

 

/* 插入元素e为队q的队尾新元素

 *插入成功返回true

 *队满返回false

*/

int queue_en(sp_queue *q, datatype e);

 

 

/* 队头元素出队

 *e返回出队元素,并返回true

 *若队空返回false

*/

int queue_de(sp_queue *q, datatype *e);

 

/* 清空队 */

void queue_clear(sp_queue *q);

 

 

/* 获得队头元素

 *队列非空,e返回队头元素,并返回true

 *否则返回false

*/

int get_front(sp_queue, datatype *e );

 

 

/* 获得队长 */

int queue_len(sp_queue q);

 

/* 遍历队 */

void queue_traverse(sp_queue q,void(*visit)(sp_queue q));

 

 

void visit(sp_queue s);

 

 

/* 接口实现文件 */

#include<stdio.h>

#include<stdlib.h>

#include"sp_queue.h"

 

 

sp_queue queue_init()

{

   sp_queue q;

   q.front = q.rear = 0;

   return q;

}

 

 

 

int queue_empty(sp_queue q)

{

   return q.front == q.rear;

}

 

 

int queue_en(sp_queue *q, datatype e)

{

   /*队满 */

   if (q -> rear == MAX_QUEUE_SIZE)

       returnfalse;

 

   /*入队 */

   q -> sp_queue_array[q -> rear] = e;

   printf("q.sp_queue_array[%d]=%d\n", q -> rear, e);

   q -> rear += 1;

   returntrue;

 

}

 

 

int queue_de(sp_queue *q, datatype *e)

{

   /*队空 */

   if(queue_empty(*q))

       returnfalse;

 

   /*出队 */

   q -> rear -= 1;

   *e = q -> sp_queue_array[q -> rear];

   returntrue;

}

 

 

void queue_clear(sp_queue *q)

{

   q -> front = q -> rear = 0;

}

 

 

int get_front(sp_queue q, datatype *e)

{

   /*队空 */

   if(q.front == q.rear)

       returnfalse;

 

   /*获取队头元素 */

   *e = q.sp_queue_array[q.front];

   returntrue;

}

 

 

int queue_len(sp_queue q)

{

   return (q.rear - q.front);

}

 

 

void queue_traverse(sp_queue q,void (*visit)(sp_queue q))

{

   visit(q);

}

 

void visit(sp_queue q)

{

   /*队空 */

   if (q.front == q.rear)

       printf("队列为空\n");

 

   int temp = q.front;

   while(temp != q.rear)

   {

       printf("%d ",q.sp_queue_array[temp]);

       temp += 1;

   }

   printf("\n");

}

 

 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值