您的位置:首页 > 理论基础 > 数据结构算法

[心得]算法和数据结构Ellis Horowitz大神知识整理

2016-10-08 00:13 531 查看
主要取材自两本书:

计算机算法C++语言描述 第2版 Ellis Horowitz et al著

数据结构基础C语言版第2版 Ellis Horowitz et al著

这个作者的写书风格很符合我这个非科班计算机从业者的胃口。数据结构基础前8章我去年仔细动手做过一遍,因此这次整理的是9~12章的高级内容。

传统算法书只对很少的几个问题给出最优算法,但对设计过程着墨较少。作者认为算法书应该以设计为主分析为辅。

算法取自一个写数学课本的波斯作家。算法指一个有限代码行,如果按其执行,可完成某一个特定任务。

有3中方法来分析平摊代价:1.聚集法;2.算账法;3.势能法。算账法最常用,另两种不好计算。

随机算法是指使用了随机发生器的算法。它分为拉斯维加斯算法和蒙特卡罗算法。前者可以重复,后者则不可重复。

任意支持查找最大最小值,插入以及删除最小值(或最大值)的数据结构类型称为优先级队列。

分治策略将输入分为k个子问题。将子问题的解拼凑成原问题的解。

分治策略例子:

从n个元素找最大最小值(I.Pohl)

快速排序(C.A.R.Hoare)

已知n个元素,想确定其中第k小的元素

int Partition(int *a,int m,int p)
{
int v=a[m];
int i=m;
int j=p;
do
{
do i++;
while(a[i]<v);
do j--;
while(a[j]>v);
if(i>j) myswap(a,i,j);
}while(i<j);
a[m] = a[j];
a[j] = v;
return j;
}

void select1(int *a, int n, int k)
{
int low=1, up=n+1;
a[n+1]=INFTY;//very big
do
{
int j = Partition(a, low, up);
if(k==j)  return;
else if(k<j) up = j;
else low=j+1;
}while(TRUE);
}


凸包常用于构造其他多种几何结构。据我所知,好多地图类应用对凸包算法应用较多。

一个平面上的点集S对应的凸包定义为包含S中所有点的最小凸多边形。凸的定义是,对于多边形内任意两点的线段都完全包含在该多边形内。

常见的问题是求得凸包的所有顶点(极值点),按照某种次序得到凸包的所有顶点。

利用分治思想,与quicksort类似,quickhull首先找出点集X中x坐标最大和最小的两个点,先假设没有x坐标值相同的点。然后这两个点连成的线段将凸包分为上凸包和下凸包两部分。

如果S是平面中的一个点集,Graham扫描可以从S中确定y坐标最小的点p,然后它将s中的点按照该点与p以及x轴正向夹角排序。最后用切线合并成最大的凸包。

#define NIL 0
#include <iostream>

struct point{
float x,y;
struct point *prev, *next;
};
typedef struct point Type;

class PointSet
{
private:
Type* ptslist;
float Area(float, float, float, float, float, float);
void PrintList(Type *);
void Scan(Type *);
void Sort(Type *);
public:
PointSet() {ptslist=NIL;}
void Insert(float a,float b);
void ConvexHull();
}

void PointSet::Scan(Type *list)
{
Type *p=list, *p1=list, *p2, *p3;
float temp;
do
{
p2=p1->next;
if(p2->next) p3 = p2->next;
else p3=p;
temp = Area(p1->x,p1->y,p2->x, p2->y, p3->x, p3->y);
if(temp>=0.0) p1=p1->next;
else
{
p1->next=p3;
p3->prev=p1;
delete p2;
p1=p1->prev;
}
}while(!(p3==p) &&(temp>=0.0));
}

void PointSet::ConvexHull()
{
Sort(ptslist);
Scan(ptslist);
PrintList(ptslist);
}


一个问题包含n个输入,要求得到它的一个子集,满足某些条件,这是贪心算法。

贪心法与动态规划的本质区别在于,贪心法只能生成一个决策序列。在动态规划中,可能生成多个决策序列。

回溯:欲求解被表达为一个n元组,其中xi是从有限集S中选取。通常待解决的问题需要找到一个向量可最大化(或最小或满足)一个准则函数。

分支定界是指那些在生成一个E节点的所有孩子之前,不会将其它活跃节点变为E节点的状态空间搜索算法。BFS广度优先就可以归类为分支定界算法。

代数变换将输入转换成更容易计算的形式。

下界是算法优化的理论极限。

一个NPC问题具有如下性质:该问题可以用多项式时间算法求解。任何答案是0或者1的问题是判定问题。任何确定给定代价函数最优值的问题称为优化问题。

其值接近最优解的有效解称为近似解。

并行算法有两个基本问题:1.前缀计算;2.表排列。

前缀计算是求给定n个输入运算的输出。

表排列的输入是以节点数组形式给出的链表。对每个节点,计算其右侧节点的个数(rank)

左倾树分高度左倾和权值左倾。

左倾树如果非空,则对所有内部节点,都有shortest(lChild)<=shortest(rChild)。

小根左倾树每个结点的关键字值都不大于其孩子节点的关键字。

最小二项式堆是小根树的聚集,它简称B堆。

小根左倾树的合并方法是:把树根关键字较大的那棵树作为树根关键字较小的那棵树的子树。

B堆是F堆的特例。

最小配偶堆是一棵小根树。在实际中,配偶堆常采用树的二叉链表表示。小根树中的兄弟节点用双向链表链在一起。

双端优先级队列DEPQ可用对称最小最大堆SMMH实现。

区间堆也是一个棵完全二叉树,树中每个结点,除最后一个结点外,都存放两个数据元素。在二叉查找树的查找过程中,每当遇到标记超出树而设置的标识时,查找都结束在外部结点,这种情形对应于查找失败。因而外部结点又称为失败结点。加入外部结点的二叉树称为扩展二叉树。二叉树的外部路径长度定义为,所有外部结点到根的路径长度之和。相应地,内部路径长度为所有内部结点到根的路径长度之和。

AVL:总保持子树的高度平衡。

定义AVL中任意子树的左右高度差不超过1.

四种旋转子树的操作:

LL新结点Y插入A的左子树的左子树。LR,RR,RL类似。LL和RR是单旋,LR和RL是双旋。

typedef struct{ int key};
typedef struct treeNOde *treeNodePointer;
struct treeNode{
treePointer lChild;
element data;
short int bf;
treePoint rChild;
};


红黑树是二叉树,splay树上自调整二叉树。

如果用于查找的数据结构大大减少存储访问,查找性能又能明显提升。对二叉树而言,存储访问和树的高度密切相关。这就是二叉树扩展到多叉树的原因。具体数量和一个块允许的值有关。

m阶B树上一棵m路查找树,它或者是空树,或者满足:

1. 根结点至少有2个孩子

2. 除根结点和外部结点外,所有的结点至少有m/2向上取整个孩子

3. 所有外部结点位于同一层

B+树的定义:或者是空树,或者满足:

1. 所有数据结点在同一层,数据结点只包含数据元素;

2. 索引结点构成一个m阶B树,每个索引结点包含关键字,但不包含数据。

3. 所有子树Ai中的数据元素其关键字小于ki+1且大于ki

数字查找树是一棵二叉树,每个结点仅包含一项数据元素。结点中存放内容取决于数据元素的二进制表示。如果关键字很长,由于在数字查找树中查找需要多次比较关键字。采用特殊的patricia结构可以大大减少关键字的比较次数。

patricia:practical algorithm to retrieve information coded in alphanumeric

思路是首先引出二路trie树,然后把该树压缩,再到处patricia树。

二路trie树是一棵仅有分支结点和数据结点的树。分支结点有lChild和rChild两个指针,但无数据;数据结点则反过来只有数据无指针。

多路trie树对于关键字变长特别有用。

消除一个孩子的分支结点常常可以提高trie树的时间性能并减少空间需求。这种trie树称为压缩trie树。

压缩二路Trie树可以用统一格式的结点表示,这种结点称为增强分支结点。增强分支结点在原分支结点中增设data域,由这种结点构成的压缩二路trie树称为patricia树。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐