当前位置: 首页 > wzjs >正文

电子商务网站建设应用关键词优化和seo

电子商务网站建设应用,关键词优化和seo,网页网站设计培训,网站建设相关书籍目录 1.堆的概念及结构 1.1堆的概念 1.2堆的结构 2.堆的实现(以大堆为例) 2.1 前提准备 2.2初始化 2.3销毁及交换函数 2.4插入及向上调整法 向上调整法 2.5删除及向下调整法 向下调整法 2.6判空、堆顶元素、元素个数 这里的堆和操作系统虚拟进程地址空间中的堆是…

目录

1.堆的概念及结构

1.1堆的概念

1.2堆的结构 

 2.堆的实现(以大堆为例)

2.1 前提准备

2.2初始化

2.3销毁及交换函数

2.4插入及向上调整法

向上调整法 

2.5删除及向下调整法

向下调整法 

2.6判空、堆顶元素、元素个数


这里的堆和操作系统虚拟进程地址空间中的堆是两回事,

一个是数据结构,一个是操作系统中管理内存的一块区域分段

1.堆的概念及结构

1.1堆的概念

一棵父亲节点的值总是不大于其子节点值的完全二叉树叫作小根堆(最小堆)

一棵父亲节点的值总是不小于其子节点值的完全二叉树叫作大根堆(最大堆),

(后续简称小堆、大堆)

1.2堆的结构 

普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费

而完全二叉树适合使用顺序结构存储,因为其每层节点从左至右连续排列,无间隔缺失

 

堆既然是一种完全二叉树,那就可以使用顺序结构的数组进行存储,即

按照从上至下从左至右的数组顺序对所有节点的值进行存储

这样,既不浪费空间,又能够高效率的遍历数据

由上图我们可以看到数组结构可以很好的模拟完全二叉树 

注意:

逻辑结构是指我们想象出来的结构,物理结构是指数据在内存中实际存储时的结构 

堆只要求了父亲节点与子节点值之间的关系,并没要求兄弟节点、堂兄弟节点值之间的关系

 2.堆的实现(以大堆为例)

前面讲了二叉树的顺序存储结构更适用于完全二叉树,

所以实现堆就是在操作数组的基础上实现堆的性质

2.1 前提准备

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>typedef int HpDateType;
typedef struct heap
{HpDateType* a;int size;int capacity;}HP;

1.包含相关头文件;2.为了便于修改数据类型重命名一下

3.定义结构体,在堆上开空间来存储相关数据

2.2初始化

//初始化
void HpInit(HP* php)
{//php指向一个堆,不能为空assert(php);php->a = (HpDateType*)malloc(sizeof(HpDateType) * 4);if (php->a == NULL){perror("malloc fail");return;}php->size = 0;php->capacity = 4;
}void HpInitArray(HP* php, HpDateType* a, int n)
{assert(php);php->a = (HpDateType*)malloc(sizeof(HpDateType) * n);if (php->a == NULL){perror("malloc fail");return;}memmove(php->a, a, n * sizeof(HpDateType));php->size = n;php->capacity = n;//建堆for (int i = (n - 2) / 2; i >= 0; --i){AdjustDown(php->a, php->size, i);}
}

 (1)无参初始化目的是预开一定的空间,

利用给定数组初始化目的是直接根据数组数据进行建堆(后续讲解)

(2)所给的堆结构体指针变量不应为空,所以断言一下

2.3销毁及交换函数

void HpDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}
//交换
void Swap(HpDateType* p1, HpDateType* p2)
{HpDateType temp = *p1;*p1 = *p2;*p2 = temp;
}

(1)销毁时需正确释放空间并更新指针及其余变量 

(2)后续频繁使用交换操作,这里单独设定一个函数

2.4插入及向上调整法

void HpPush(HP* php, HpDateType x)
{assert(php);//扩容if (php->capacity == php->size){HpDateType* temp = (HpDateType*)realloc(php->a, sizeof(HpDateType) * php->capacity * 2);if (temp == NULL){perror("malloc fail");return;}php->a = temp;php->capacity *= 2;}//实现插入,插入到末尾,实现大堆//需要依次与父亲进行比较,即向上调整php->a[php->size++] = x;AdjustUp(php->a, php->size - 1);
}

(1)插入数据第一步,思考扩容

(2)顺序存储结构中,尾插效率更高,先将数据插入到尾部

(3)为了实现大堆,需要将所插入的数据进行调整,即AdjustUp();

向上调整法 

向上调整法的前提是数据插入前本身就是一个堆

逻辑结构上

如果所插入数据比其祖先节点的值大就进行交换,否则就不动,最终实现大堆

具体操作体现在物理结构,即数组上

通过下标间的关系,parent = ( child - 1 ) / 2 (计算机整除运算自动向下取整)

依次找到尾节点的祖先节点,然后比较数据大小,大就交换,小就停止交换

    int parent = (child - 1) / 2;
while (){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}

这显然是一个循环!

通过前面的分析,我们很容易知道, 情况最坏是,所插入数据需要与根节点的值进行交换,自然地,就会把 parent(父亲节点下标)大于等于0作为循环结束条件,但正如上述代码所展示的一样,通过迭代更新父子节点的下标, parent恒大于等于0(最坏情况当child等于0时也成立),也就是说如果循环内部不能控制住结束条件,这将是一个 死循环
观察到, 所插入数据与根节点的值进行交换后,child 更新为 0 , parent仍等于0                  那么就将       child  > 0      作为循环结束条件
void AdjustUp(HpDateType* a, int child)
{//给定数组为空时,没必要进行下面步骤assert(a);int parent = (child - 1) / 2;//parent恒大于等于0while (child > 0){if (a[child] > a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

2.5删除及向下调整法

void HpPop(HP* php)
{assert(php);//assert(!HpEmpty());//删除数据,只删除堆顶的数据Swap(&php->a[0], &php->a[php->size - 1]);php->size--;//向下调整,实现大堆AdjustDown(php->a, php->size, 0);
}

(1)数组中,尾删的效率较高,其余位置的删除操作都会因为移动数据造成效率低下

(2)堆的删除操作是针对堆顶元素的删除,原因如下:

在大堆中,最大元素位于堆顶,删除之后通过向下调整法(后续讲解) 次大元素就会位于堆顶

这样的删除更具功能性,更有利于在现有基础上直接找到最大元素

(3)具体操作就是先将堆顶元素与最后一个数据元素进行交换,然后删除堆顶元素,

最后对余下数据进行向下调整操作,使其重新成为一个大堆

向下调整法 

向下调整法的前提是所调整节点的左右子树是一个堆

逻辑结构上

如果该节点数据比其孩子节点中的较大值小就进行交换,否则就不动,最终实现大堆

具体操作体现在物理结构,即数组上

通过下标间的关系,leftchild = parent * 2 + 1 (计算机整除运算自动向下取整)

rightchild = leftchild + 1,依次找到该节点的孩子节点

然后与孩子节点中的较大值进行比较,大就交换,小就停止交换

int child = parent * 2 + 1;while ()
{//左孩子一个逻辑,右孩子一个逻辑,直接假设//child是左右孩子中较小的一个孩子的下标//注意右孩子的有无(防止越界访问与无效数据)if (child + 1 < n && a[child] > a[child + 1]){++child;}//与左右孩子中较大的一个孩子进行比较if (a[parent] > a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}
}

这显然是一个循环!

向下调整时,

(1)父亲节点有孩子节点时,就需要与孩子节点的值进行一次比较,所以 左孩子节点的下标小于元素个数,即 child < n 可作为循环结束条件

(2)交换操作的实质是如果父亲节点值比孩子节点中的较大值小,就进行交换,否则就不动

那么我们就先假设左孩子节点的值较大,再将左孩子节点的值与右孩子节点值进行比较,更新孩子节点,然后与父亲节点的值进行比较,从而简化比较交换操作

需要进行比较然后进行相同的操作时,先假设再判断更新的方法更好

(3)注意右孩子的有无(防止越界访问与无效数据)

if (child + 1 < n && a[child] > a[child + 1])

必须先判断右孩子的有无,再进行访问操作,否则就是越界访问或无效数据!

void AdjustDown(HpDateType* a, int n, int parent)
{int child = parent * 2 + 1;//有左孩子才进行调整while (child < n)//n是节点个数{//左孩子一个逻辑,右孩子一个逻辑,直接假设//child是左右孩子中较小的一个孩子的下标//注意右孩子的有无(防止越界访问与无效数据)if (child + 1 < n && a[child] > a[child + 1]){++child;}//与左右孩子中较大的一个孩子进行比较if (a[parent] > a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}

2.6判空、堆顶元素、元素个数

//判空
bool HpEmpty(HP* php)
{assert(php);return php->size == 0;
}
//堆顶元素
HpDateType HpTop(HP* php)
{//assert(php);//一举两得assert(!HpEmpty(php));return php->a[0];
}
//大小
int HpSize(HP* php)
{assert(php);return php->size;
}

(1)注意相关断言

(2)根据意义直接返回相应值即可

http://www.dtcms.com/wzjs/148678.html

相关文章:

  • 国外那些网站是做菠菜的百度平台客服
  • 荆门城乡建设局网站百度普通下载
  • 做DJ网站违法吗自己做网站怎么做
  • 广州做网站哪家强网址查询
  • 做印刷在哪个网站接单好好百度优化服务
  • 企业网站建设排名网站推广优化网址
  • wap手机网站制作营销策略有哪些4种
  • 如何成立一个房产网站公司网站推广方法
  • 专注企业网站建设网络营销步骤
  • 网站开发维护合同模板电子版中国最新消息新闻
  • 画册设计流程手机百度seo快速排名
  • 淄博做网站优化宣传推广的十种方式
  • 做的好的地方网站免费seo软件推荐
  • 阿里国际网站做免费有用吗域名信息查询系统
  • 合肥手机网站建设哪个浏览器看黄页最快夸克浏览器
  • 做网站品seo资讯
  • 武汉高端网站建设公司做推广的都是怎么推
  • 厦门网站建设及维护百度品牌
  • 批量导文章到wordpress郑州专业seo推荐
  • 郑州 外包网站百度手机助手app免费下载
  • 找人做网站都要提供什么长沙网站关键词排名
  • windows 做网站服务器运营推广的方式和渠道
  • 网站建设维护方案ppt最近国内新闻
  • 长春 美容 网站建设媒体软文发稿
  • 镇江企业网站建设谷歌推广一年多少钱
  • 从网络安全角度考量_写出建设一个大型电影网站规划方案吉林seo关键词
  • 做公司网站需注意什么深圳seo公司
  • 河北建设网网站教育机构网站
  • 织梦网站文章内容模板博客网站登录入口
  • 河南省建设厅执业资格注册中心seo优化排名教程