基础程序算法笔记

二分搜索(Binary Search)

时间复杂度 :
假使总共有n个元素,那么二分后每次查找的区间大小就是n,n/2,n/4,…,n/2^k(接下来操作元素的剩余个数),其中k就是循环的次数。 
最坏的情况是K次二分之后,每个区间的大小为1,找到想要的元素 
令n/2^k=1, 
可得k=log2n,(是以2为底,n的对数),所以时间复杂度可以表示O()=O(logn).

int BinarySearch(int[] list, int target){
    int left = 0;
    int right = list.length-1;
    
    while(left <= right)
    {
        int mid = (right + left)/2;
        if(list[mid] == target)
            return mid;
        elseif(list[mid] < target)
            left = mid + 1;
        elseif(list[mid] > target)
            right = mid - 1;
    }
    return -1;
}


分治思想

基本特征:

1.问题缩小到一定规模容易解决

2.分解成的子问题是相同种类的子问题,即该问题具有最优子结构性质

3.分解而成的小问题在解决后要可以合并

4.子问题是相互独立的,即子问题之间没有公共的子问题

经典hanoi塔

void hanoi(n, a, b, c){
    if(n == 1)
    {
        cout<<a<<"->"<<c<<endl;
    }
    else
    {    
        hanoi(n-1, a, c, b);
        cout<<a<<"->"<<c<<endl;
        hanoi(n-1, b, a, c);
    }
}

main()
{
    int n = 3;
    hanoi(n, a, b, c);
}

 

宽度优先搜索Breadth First Search

BFS使用队列(queue)来实施算法过程,队列(queue)有着先进先出FIFO(First Input First Output)的特性,BFS操作步骤如下: 
1、把起始点放入queue; 
2、重复下述2步骤,直到queue为空为止: 
1) 从queue中取出队列头的点; 
2) 找出与此点邻接的且尚未遍历的点,进行标记,然后全部放入queue中。

数组表示:查找每个顶点的邻接点所需时间为O(n2),n为顶点数,算法的时间复杂度为O(n2)

# 利用队列实现树的广度优先遍历
def level_queue(root):
    if root is None:
        return
    my_queue=[]
    node = root
    my_queue.append(node)
    while my_queue:
        node=my_queue.pop(0)
        print(node.elem)
        if node.lchild is not None:
            my_queue.append(node.lchild)
        if node.rchild is not None:
            my_queue.append(node.rchild)

 

深度优先搜索Depth First Search

DFS的实现方式相比于BFS应该说大同小异,只是把queue换成了stack而已,stack具有后进先出LIFO(Last Input First Output)的特性,DFS的操作步骤如下: 
1、把起始点放入stack; 
2、重复下述3步骤,直到stack为空为止:

  • 从stack中访问栈顶的点;
  • 找出与此点邻接的且尚未遍历的点,进行标记,然后全部放入stack中;
  • 如果此点没有尚未遍历的邻接点,则将此点从stack中弹出。

 

数组表示:查找所有顶点的所有邻接点所需时间为O(n2),n为顶点数,算法时间复杂度为O(n2) 

# 利用递归实现深度优先
def depth_tree(tree_node):
    if tree_node is not None:
        print(tree_node._data)
        if tree_node._left is not None:
            return depth_tree(tree_node._left)
        if tree_node._reght is not None:
            return depth_tree(tree_node._reght)

 

快速排序

快速排序基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

 

package test;



public class test {
    public static void main(String[] args) {
        int [] array={4,8,6,9,7,1,3,2,5};
        QuickSort(array,0,array.length-1);
        for(int i=0;i<array.length;i++)
        {
            System.out.print(array[i]+" ");
        }
    }


    public static void QuickSort(int [] array,int start,int end)
    {
        int low=start;
        int high=end;
        int key=array[low];
        while(low<high)
        {
            while(low<high&&array[high]>=key)
                high--;//当end结点值大于基准值时,向前移动,直到找到小于基准值的值
            if(low<high)
            {
                array[low]=array[high];
                low++;
            }
            while(low<high&&array[low]<=key)low++;
            if(low<high)
            {
                array[high]=array[low];
                high--;
            }
        }
        array[low]=key;//此时start和end 已经指向同一元素
        if(low-1>start)QuickSort(array,start,low-1);
        if(high+1<end)QuickSort(array,high+1,end);
    }
}

 

随机选取数据

假设有一个集合A(a_1, ..., a_n),对于数m,0<=m<=n,如何从集合A中等概率地选取m个元素

通过计算古典概率公式可以得到,每个元素被选取的概率为m/n。如果集合A里面的元素本来就具有随机性,每个元素在各个位置上出现的概率相等,并且只在A上选取一次数据,那么直接返回A的前面m个元素就可以了,或者可以采取每隔k个元素取一个等类似的方法。

(1)假设集合A中的元素在各个位置上不具有随机性,比如已经按照某种方式排序了,那么我们可以便利集合A中的每一个元素a_i,0<=n根据一定的概率选取ai。

设m'为还需要从A中选取的元素个数,n'为元素a_i及其右边的元素个数,也即n'=(n-i+1)。那么选取元素a_i的概率为m'/n'。
我们简单计算一下前面两个元素(2<=m<=n)各被选中的概率。
1)设p(a_i=1)表示a_i被选中的概率。显而易见,p(a_1=1)=m/n,p(a_1=0)为(n-m)/n;
2)第二个元素被选中的概率为
p(a_2=1) = p(a_2=1,a_1=1)+p(a_2=1,a_1=0)
= p(a_1=1)*p(a_2=1|a_1=1)+p(a_1=0)*p(a_2=1|a_1=0)
= m/n * (m-1)/(n-1) + (n-m)/n*m/(n-1)
= m/n

c++实现上述算法
template<class T>
bool getRand(const vector vecData, int m, verctor& vecRand)
{
    int32_t nSize = vecData.size()
    if(nSize < m || m < 0)
        return false;
    vecRand.clear();
        vecRand.reserve(m);
    for(int32_t i = 0, isize = nSize; i < isize; i++){
        float fRand = frand();
        if(fRand <=(float)(m)/nSize){
            vecRand.push_back(vecData[i]);
            m--;
        }
        nSize --;
    }
    return true;
}

A*算法

A*算法原理:

open列表:记录所有被考虑来寻找最短路径的方块

closed列表:记录下不会再被考虑的方块

G值:从开始点A到当前方块的移动量

H值:从当前方块到终点的移动量估算值

F值(和值):每个方块的和值 F=G+H

重复以下步骤来找到最短路径:

1.将方块添加到open列表中,该列表有最小的和值。且将这个方块成为S吧

2.将S从open列表移除,然后添加S到closed列表中。

3.对于与S相邻的每一块可通行的方块T:

-如果T在closed列表中:不管它。

-如果T不在open列表中:添加它然后计算出它的和值。

-如果T已经在open列表中:当我们使用当前生成的路径达到那里时,检查F和值是否更小。如果是,更新它的和值和它的前继。

[openList add:originalSquare]; // start by adding the original position to the open list
do {
	currentSquare = [openList squareWithLowestFScore]; // Get the square with the lowest F score
 
	[closedList add:currentSquare]; // add the current square to the closed list
	[openList remove:currentSquare]; // remove it to the open list
 
	if ([closedList contains:destinationSquare]) { // if we added the destination to the closed list, we've found a path
		// PATH FOUND
		break; // break the loop
	}
 
	adjacentSquares = [currentSquare walkableAdjacentSquares]; // Retrieve all its walkable adjacent squares
 
	foreach (aSquare in adjacentSquares) {
 
		if ([closedList contains:aSquare]) { // if this adjacent square is already in the closed list ignore it
			continue; // Go to the next adjacent square
		}
 
		if (![openList contains:aSquare]) { // if its not in the open list
 
			// compute its score, set the parent
			[openList add:aSquare]; // and add it to the open list
 
		} else { // if its already in the open list
 
			// test if using the current G score make the aSquare F score lower, if yes update the parent because it means its a better path
 
		}
	}
 
} while(![openList isEmpty]); // Continue until there is no more available square in the open list (which means there is no path)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Pat晴神宝典是一本关于算法笔记。它由知名的算法专家Pat编写,是一本系统全面的算法学习资料。这本宝典包含了许多不同类型的算法,涉及了各个领域的问题解决方法。 Pat晴神宝典首先介绍了算法基础知识,如时间复杂度、空间复杂度、数据结构等。然后它深入探讨了各种经典的算法,如排序算法、搜索算法、图算法等。每个算法都有详细的说明和代码实现,以及算法的优缺点和应用场景。宝典还提供了大量的练习题和习题解答,帮助读者巩固所学的算法知识。 Pat晴神宝典不仅仅是一个算法的技术手册,它还讲述了算法的设计思想和解题方法。宝典中有许多实际问题的案例分析,解释了如何使用不同的算法解决实际问题。它还提供了一些常见算法的优化方法和改进思路,帮助读者更好地掌握算法的运用。 总结来说,Pat晴神宝典是一本涵盖了广泛的算法知识的笔记。无论是初学者还是有经验的程序员,都可以从中获得宝贵的算法学习和应用经验。它不仅帮助读者提高解决问题的能力,还培养了读者的算法思维和创造力。无论在学术研究还是工程开发中,这本宝典都是一本不可或缺的参考书。 ### 回答2: PAT晴神宝典是一本算法学习笔记。PAT(Programming Ability Test)是中国程序设计竞赛的一种形式,它旨在提高学生的程序设计能力和算法思维能力。晴神指的是晴天老师,他是一位在算法竞赛界非常有影响力的老师,他编写了《算法笔记》一书。 这本《算法笔记》包含了程序设计竞赛中常用的数据结构和算法的讲解和实践。它主要分为四个部分:基础部分、数据结构、算法以及习题。基础部分主要介绍了程序设计的基本开发环境以及常用的算法思想和技巧,如递归、分治和动态规划等。数据结构部分涵盖了常见的数据结构,如树、图和堆等,以及它们的实现和应用。算法部分介绍了各种算法的设计思想和实现方法,如贪心算法、搜索算法和图论算法等。习题部分提供了大量的练习题,并给出了详细的解题思路和代码。 《算法笔记》以简洁清晰的语言、丰富的例子和详细的讲解,帮助读者掌握算法的基本原理和应用技巧。它不仅适用于想要参加编程竞赛的学生和程序员,也适用于对算法感兴趣的人士。通过阅读该书,读者能够系统地学习和应用算法,提高编程能力和算法思维能力。 总之,PAT晴神宝典是一本覆盖广泛且深入浅出的算法学习笔记,对于学习和应用算法的人士来说,它是一本十分有价值的资源。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值