记录-常见算法的收集

1,快速排序--找到基准点的位置

既不浪费空间又可以快一点的排序算法。

如:“6 1 2 7 9 3 4 5 10 8”这10个数进行排序。首先找到一个数作为基准点(一个参照数),为了方便,让第一个数6作为基准点。然后将这个序列中所有比基准数大的数放在6右边,比基准点小的数放在6的左边,类似这种:“3 1 2 5 4 6 9 7 10 8”.

相当于每一次快速排序,就将基准点的位置确定了,然后,比基准点小的数在位置左边,比基准点大的数在位置右边,然后再选取新的基准点,再进行快速排序。)

解释:分别在初始序列“6 1 2 7 9 3 4 5 10 8”两端开始“探测”。从右到左找小于6的数,从左到右找大于6的数,然后交换他们。

这里用i和j,分别指向序列最左边和最右边。即i=1,指向数字6,j=10,指向数字。

首先j开始行动。因为此处设置的基准数是最左边的数,所以需要j先动。

j向左移动(j--),直到找到一个小于6的数停下。

然后i向右移动(i++),直到找到一个大于6的数停下。

例子里,j是在数字5的位置,i是在数字7的位置上。


交换i和j位置上的数字,这样:“6 1 2 5 9 3 4 7 10 8”。

到此,第一次交换结束。

然后,继续让j向左移动,找比6小的数,即“4”。

让i向右移动,找到比6大的数,即“9”。

进行交换,这样:“6 1 2 5 4 3 9 7 10 8”。第二次交换结束。

继续这样移动,找值,j发现了3,停下。i向右移动,遇到了j。说明“探测”结束。

将基准数6和3交换,这个位置定为基准数的位置。“3 1 2 5 4 6 9 7 10 8”.


第一次的“探测”结束(可以理解为一次快速排序结束,基准点找到了位置)。

过程:j找到小于基准数的数,i找到大于基准数的数,直到i和j相遇。

接下来,要以基准点6,分为两个序列,左边“3 1 2 5 4”,右边“9 7 10 8”。

按照以上的方法,处理两个序列。

左边:“3 1 2 5 4”。以3为基准点,3的左边都小于等于3,3的右边都大于等于3.

            结果“2 1 3 5 4”。i和j相遇,值交换,3以归位。

             然后继续分为两个序列,“2 1”和“5 4”,在排序。

             这样左边结束后,结果“1 2 3 4 5 6 9 7 10 8”。

右边:“9 7 10 8”。同理,得到“1 2 3 4 5 6 7 8 9 10”。


分析:快速排序比较快,以外每次交换都是跳跃式的。每次交换不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离大了,交换的次数也就少了。

           当然在最坏的情况下,还是可能相邻的两个数进行交换,所以快速排序的zui最差时间复杂度和冒泡排序是一样的O(N2)平均时间复杂度O(NlogN)

代码(c++):

#include <stdio.h>
int a[101],n;  //全局变量
void quicksort(int left,int right)  //位置,索引
{
    int i,j,t,temp;
    if(left>right) return;
    temp=a[left];  //temp中存的是基准数
    i=left;
    j=right;
    while(i!=j)
    {
        while(a[j]>=temp && i<j)  //顺序很重要,从右边先开始,找小于基准点的数
            j--;
        while(a[i]<=temp && i<j)  //找大于基准点的数
            i++;
        if(i<j)  //交换位置
        {
            t=a[i];
            a[i]=a[j];
            a[j]=t;    
        }
    }
    //基准数归位
    a[left]=a[i];
    a[i]=temp;
    quicksort(left,i-1); //处理左边的,递归
    quicksort(i+1,right); //处理右边的,递归
}

抄录于:详细快速排序

代码(java):

public void quick_sort(int []a,int left,int right){
    if(left>right)  return;
    int i=left;
    int j=right;
    int temp=a[left];
    while(i!=j){
        while(i<j && a[j]>=temp)
            j--;
        while(i<j && a[i]<=temp)
            i++;
        if(i<j){
            int tt=a[i];
            a[i]=a[j];
            a[j]=tt;
        }
    }
    int kk=a[i];
    a[i]=temp;
    a[left]=kk;
    quick_sort(a,left,i-1);
    quick_sort(a,j+1,right);
}

2,冒泡排序--相邻比较,找到最值

基本思想:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到无序队列的队尾,从而成为有序序列的一部分;然后继续这个过程。

通过两两比较交换位置,选出剩余无序序列中最大(小)的数据元素放到队尾。

时间复杂度:O(N2)也有说最优时间复杂度是O(n),这里不提。空间复杂度:O(1)。

过程:1,比较相邻的元素。如果第一个比第二个大(小),交换。

           2,对每一对相邻元素做同样的工作,从开始到结尾,最后的元素是最大(小)的数。

           3,针对所有的元素重复以上步骤,除了有序的元素。(已选出的元素)

            4,持续对无序元素重复以上步骤,直到都有序。

例如:


以上为例(小到大):

        第一次排序,3,6比较,不需要交换。6,4比较,交换得到4,6。

                             6,2比较,交换得2,6。  6,11比较,不交换。

                             11,10比较,交换得10,11。11,5比较,交换得5,11。

                              得到“3 4 2 6 10 5 11”。

        之后的排序最后有序的序列不参与,元素两者之间的比较。得到最大值,放在无序序列的队尾。

代码(c++):

void bubble_sort(int arr[],int len){
    int i,j;
    for(i=0;i<len-1;i++){
        for(j=0;j<len-1-i;j++){ //无序序列长度
            if(arr[j]>arr[j+1])
                swap(arr[j],arr[j+1]);
        }
    }
}

代码(java):

public static void bubble_sort(int[] arr){
    int i,j,temp,len=arr.length;
    for(i=0;i<len-1;i++){
        for(j=0;j<len-1-i;j++){
            if(arr[j]>arr[j+1]){
                temp=arr[j];
                arr[j]=arr[j+1];
                arr[j+1]=temp;
            }
        }
    }
}

3,二分查找算法--数组中以中间值二分查找数

二分查找算法是在有序数组中用到较为频繁的一种查找算法。对数组一直进行二分,然后查找到数

对数组进行遍历,每个元素进行比较,其时间是O(n)。二分查找则是O(lgn)。

重点:二分查找的时间复杂度O(logn)。最坏的情况下是O(n)

           二分查找的条件是待查询的数组是有序的,我们假设数组是升序。

            二分查找主要思路:设定两个指针start和end分别指向数组的首尾两端,然后比较数组中间节点array[mid]和待查找元素。如果待查找元素小于中间元素,那么表明待查找元素在数组的前半段,那么将end=mid-1;如果待查找元素大于中间元素,那么表明待查找元素在数组的后半段,那么将start=mid+1;如果待查找元素等于中间元素,那么就是mid的值。

例如,{1,2,3,4,5,6,7,8,9}查找6:

        1,中间元素mid=(start+end)/2,即5。5<6,所有,6在{6,7,8,9}中。

        2,{6,7,8,9}中间元素,即8。8>6,元素在{6,7,8}中查找。

        3,{6,7,8}中间元素,即7。7>6,左边数组只剩下6,找到了。

代码(java):

public class BinarySearch {  
public static void main(String[] args) {  
int [] array = {1,2,3,4,4,7,12};  
int len = array.length;   
}  
/**  
 * 二分查找(递归)  
 * @param arry 递增数组  
 * @param value 待查找数值  
 * @param start 起始查找位置  
 * @param end 末查找位置  
 * @return  
 */  
private static int binarySearchRecursion(int arry[],int value,int start,int end)  
{  
    if(start > end)  
        return -1;  
    int mid=start + (end-start)/2;  
    if(arry[mid] == value)  
        return mid;  
    else if(value < arry[mid])  
    {  
        end = mid - 1;  
        return binarySearchRecursion(arry,value,start,end);  
    }  
    else  
    {  
        start = mid + 1;  
        return binarySearchRecursion(arry,value,start,end);  
    }  
}  
/**  
 * 二分查找(非递归,循环)  
 * @param arry 递增数组  
 * @param value 待查找数值  
 * @param start 起始查找位置  
 * @param end 末查找位置  
 * @return  
 */  
private static int binarySearchRecursionNon(int arry[],int value,int start,int end)  
{  
while(start <= end){  
    int mid=start + (end-start)/2;  //或者是 (start+end)/2
    if(arry[mid] == value)  
        return mid;  
    else if(value < arry[mid])  
    {  
        end = mid - 1;  
    }  
    else  
        start = mid + 1;  
}  
return -1;  
}  
}  

时间复杂度:外循环和内循环以及判断和交换元素的时间开销。最优情况是开始就排好序了,不用交换元素,最坏的是逆序。

空间复杂度:在交换元素时那个临时变量所占的内存空间。最优情况是开始就排好序了,不用交换元素,最坏的是逆序。

这些是自己的一些记录收集和理解。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值