算法练习-排序算法

//这里准备用策略模式写一个排序系统,从小到大排序
//先写一个测试类
public class Ztest{ //不用括号Ztest()
    public static void main (String[] args){
        Sorter testsorter = new MergeSorter();
        Integer[] a = new Integer[]{5,5,8,9,34,3,56,6,7,0};
        //只有String和Integer默认实现了Comparable方法
        //然后注意这里初始化非基本类型数组采用的方式
        testsorter.sort(a); //自动识别类型
        for(Integer i:a) System.out.println(i); //这里是打印i,不是a[i]
    }
}

//定义一个基类,不同的策略是它的子类中的同名方法
//行业上更习惯把基类搞成接口
interface Sorter{ //不用public,默认就是
    public <T extends Comparable<T>> void sort(T[] list); //(这个T extends Comparable<T> 非常有意思,它的意思是:所有Comparable类的子类可以作为实际参数赋值给T,另外,这个类本身需要参数,而且在这里,这两个参数必须一样)
}

//【1】第一个是简单的选择排序
//思路非常简单直接,第一步找出最小的(或最大的)元素,放在一头,然后依次重复,最后排序结束
//然后怎么找最小的,使用比较,用一个temp值和一个temp序号作为比较器。不对,不用一个temp值作为比较器,只需要一个temp序号
class ChooseSorter implements Sorter{
    public <T extends Comparable<T>> void sort(T[] list){
        for(int j = 0;j<list.length-2;j++){
            int minnumb = j ;
            for(int i = 1;i<list.length-1;i++){
                if (list[i].compareTo(list[minnumb])<0){
                    minnumb = i;
                }
            }
            //第一重循环到这里就找出了第一个最小值,然后进行交换
            Integer temp = list[minnumb];
            list[minnumb] = list[j];
            list[j] = temp;
            //然后在外面再套一层循环,OK
        }
    }
}

//【2】第二个是插入排序

//【3】第三个是归并排序
//归并排序真的非常吊,感觉把分冶思想用到极致了,据说这个其实比快排要快
//归并的具体方法是,先分,再边合边排序
//【3.1】
class MergeSorter implements Sorter{
    public <T extends Comparable<T>> void sort(T[] list){ //这里和第二个方法间可以使用方法重载,也可以另外命名方法,我这里就直接重载了
        T[] temp = (T[]) new Comparable[list.length];
        //归并排序不能原地排序,还需要一个同等大小的数组空间
        //这个东西我觉得可以作为类的对象在方法中被赋值之后被调用,也可以在方法中申明,然后不断作为参数传递(免得不断新建,节省空间?),是一样的
        //这个东西的另一个实现方式是先把list复制到temp中,最后在merge的时候一个个覆盖回list中,这种方法要快一些,只是注意复制的时候不要复制错了
        //然后这里的这个temp的声明形式也是非常有意思
        sort(temp,list,0,list.length-1);//以后记得还是用length-1,然后判断边界用<=,因为不这样做的话在其他的复杂一点的边界计算中容易出错
    }
    public <T extends Comparable<T>> void sort(T[] temp,T[] list,int start ,int end){
        if (start == end){ //先写跳出循环
            return; //直接跳出这个函数就行了,不用返回什么
        }
        else if(start < end){
            int mid = start+(end-start)/2; //防止溢出int,先定义也省的算两次

            //这三句是核心算法
            sort(temp,list,start,mid); //分冶
            sort(temp,list,mid+1,end);
            merge(temp,list,start,mid,end); //合并的同时排序
        }
    }
    //merge方法说起来非常简单,但是实现起来还是有点费劳力的,而且有些坑(边界,如果是i<=k之后还有++,就意味着这时候i=k+1)
    public <T extends Comparable<T>> void merge(T[] temp,T[] list,int start ,int mid,int end){

        int i,j,k;
        for (i=start;i<=end;i++){
            temp[i] = list[i]; //先复制进temp
        }

        //这是merge方法的核心
        for (i=0,j=0,k=0;start+i<=mid&&mid+1+j<=end;){
        //不要写错,++不要写到这里
        //有三个指针,不要漏了
        //这里的跳出语句是一个且判断,感觉有些笨拙了,应该有更加灵活一些的方法
            if (temp[start+i].compareTo(temp[mid+1+j]) < 0){
                list[start+k]=temp[start+i];
                i++;k++; //这是两个语句,之间不能是逗号,必须分号
            }else { //相等的情况放到这也没问题
                list[start+k]=temp[mid+1+j];
                j++;k++;
            }
        }
        //看k指针有没有指到头,也就是start+k是否等于end,等于就巧了,直接返回,要是不等于,就说明有个子数组还有数,再看另外两个指针,判断出哪个没完就把哪个复制过去
        if (start+k == end+1) return; //卧槽,调出来了,这个边界也是非常蛋疼啊
        else{
            if (start+i == end+1){ //第一个完了,于是把第二个的后边复制过去
                for (;mid+1+j<=end;j++,k++) list[start+k]=temp[mid+1+j];
            }else{
                for (;start+i<=mid;i++,k++) list[start+k]=temp[start+i];
            }
        }
    }
}

//【4】第四个是快排
class QuickSorter implements Sorter{
    @Override
    public <T extends Comparable<T>> void sort(T[] list){

    }
}

//【5】第五个是冒泡排序
//冒泡的关键不是移动某个值,而是关注位置
//按顺序从前往后比较并交换每相邻两个位置中的值
//【5.1】
class BubbleSorter implements Sorter{
    @override
    public <T extends Comparable<T>> void sort(T[] list){
        int i,j;
        T temp; //这块不要申明错了,放到Int里边去了

        //这两个for循环和里边的交换判断 是核心算法
        for (i=list.length-2;i>=0;i--){
        //这里i和j的边界琢磨起来还是好麻烦啊
        //另外默认list有 .length 属性
            for (j=0;j<=i;j++){
                if(list[j].compareTo(list[j+1])>0){
                    //如果左边的数大于右边的数,就交换这两个数
                    //如果不大于的话就直接过,不用其他的了,break什么的也不用
                    //下面的交换应该很熟练了
                    temp = list[i];
                    list[i] = list[i+1];
                    list[i+1] = temp;
                }
            }
        }
    }
}
//【5.2】一个改进,加入一个状态tag
class BubbleSorter implements Sorter{
    @Override //O要大写
    public <T extends Comparable<T>> void sort(T[] list){
        int i,j;
        T temp;
        boolean tag = true;
        //在这加入一个状态机,当有一轮冒泡的时候出现一次交换都没有的情况的话,就说明前面的都是有序的了,就不用再冒泡了
        //可以通过在后边加一个If判断来break,更简单的方法是把判断放到for语句中
        //开始的时候设置状态机初始值
        for (i=list.length-2;i>=0&&(tag==true);i--){ //这个tag==true其实可以直接是tag
            tag = false;
            //在进入下层循环之前修改状态机,只有下层循环中的if语句执行了,修改回来了状态机,才能继续上层循环
            //为什么不把这句放到下一层循环中if之前,因为只需要一轮冒泡中有一次交换就行了
            for (j=0;j<=i;j++){
                if(list[j].compareTo(list[j+1])>0){
                    temp = list[j];
                    list[j] = list[j+1];
                    list[j+1] = temp;

                    tag = true;
                }
            }
        }
    }
}
时间: 2024-11-03 12:27:24

算法练习-排序算法的相关文章

【C/C++学院】0907-象棋五子棋代码分析/寻找算法以及排序算法

象棋五子棋代码分析 编译代码报错: 错误 1 error MSB8031: Building an MFC project for a non-Unicode character set is deprecated. You must change the project property to Unicode or download an additional library. See http://go.microsoft.com/fwlink/p/?LinkId=286820 for mo

STL算法之排序算法

STL排序算法通常复杂度坏于线性,且必须要random-access Iterators. 所以,forward_list, list, associative and unordered contains 不提供随机访问迭代器,这些容器不能用排序算法. 但是,forward_list,list提供了成员函数sort,associative contains 自动排序,unordered contains不能排序. 通常,排序元素一次要比保持元素有序要更快.STL提供了不同的排序算法,根据需求选

c/c++ 通用的(泛型)算法 之 只读算法,写算法,排序算法

通用的(泛型)算法 之 只读算法,写算法,排序算法 只读算法: 函数名 功能描述 accumulate 求容器里元素的和 equal 比较2个容器里的元素 写算法 函数名 功能描述 fill 用给定值,覆盖给定的范围的元素 fill_n 用给定值,覆盖给定开始位置后的,n个元素变 back_inserter 在容器末尾插入元素 copy 把容器1指定范围里的值拷贝给容器2,并返回指向容器2最后一个元素的下个元素 replace 用某个值替换掉给定范围的某个值 replace_copy 用某个值替

在Object-C中学习数据结构与算法之排序算法

笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速排序 双路快速排序 三路快速排序 堆排序 总结与收获 参考与阅读 选择排序 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n2) 的时间复杂度.所以用到它的时候,数据规模越小越好.唯一的好处可能就是不占用额外的内存空间了吧. 1.算法步骤 首先在未排序序列中找到最小(大)元素,存放到排

算法之排序算法总结

算法之排序算法总结 | Carrie博客 全部 全部 博客 友链 关于 ps:这里的排序都是从小到大进行排列. 冒泡排序 算法思想:从第一个数开始,将两个相邻的数进行比较,如果前一个数大于后一个数,则互换位置,否则保持不变.这样比较一趟,可以把最大的数放在末尾(根据循环的趟数决定).依次循环,直到排序完成. 时间复杂度:O(n^2) 大专栏  算法之排序算法总结li>空间复杂度:O(1) 选择排序 算法思想:从待排序的数字中找出最小的数,放在排序数字的最开始,之后依次在未排序的数字中选出最小的数

算法学习-排序算法

数据结构-算法复杂度 时间复杂度 事件频度 一个算法花费的时间与算法种语句的执行次数成正比,哪个算法种语句执行次数多,它花费时间就多. 一个算法中的语句执行次数称为语句频度或时间频度.记为T(n) eg:计算1-100的和 方法一:for循环 T(n) = n + 1 方法二:直接计算 T(n) = 1 时间复杂度 一般情况下,算法中的基本操作语句的重复执行次数时问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n) / f(n) 的极限值为不等于0的常

javascript数据结构与算法--高级排序算法

高级排序算法是处理大型数据集的最高效排序算法,它是处理的数据集可以达到上百万个元素,而不仅仅是几百个或者几千个.现在我们来学习下2种高级排序算法---- 希尔排序和快速排序. 一:希尔排序: 希尔排序的核心理念是:首先比较距离较远的元素,而非相邻的元素. 基本原理:通过定义一个间隔序列来表示在排序过程中进行比较的元素之间有多远的间隔. 下面我们来看看数组[0,9,1,8,7,6,2,3,5,4] 来使用希尔排序的原理:如下图: 代码分析如下: 1. 执行 "间隔序列=3的步骤" A.

stl_algorithm算法之排序算法

排序算法: 注意:容器中必须重载 op< ,排序中stl标准中要求用小于来进行比较. 7.53.sort //全排序. 7.54.stable_sort //稳定排序.两个或两个以上的相邻且相等的元素是不会进行相对位置的变化的. 7.55.partial_sort //部分排序.会先调用sort得到指定个数的全部排序的结果,而调用sort只是中间过程.结果是 //除了指定个数之外其他的元素该是如何还是如何. 7.56.partial_sort_copy //获得部分排序个数的结果. 7.57.t

数据结构与算法 4:排序算法,选择/插入/冒泡/希尔/快速/归并

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] 排序算法 平均复杂度 冒泡排序    O(n2) 选择排序     O(n2) 插入排序     O(n2) 希尔排序     O(n1.5) 快速排序    O(N*logN) 归并排序     O(N*logN) 堆排序     O(N*logN) 基数排序     O(d(n+r)) 选择排序: [email protected]://990487026.blog.51cto.com~/sort$ c

【每日算法】排序算法总结(复杂度&amp;稳定性)

一.插入排序:稳定,时间复杂度O(n^2) 想象你在打扑克牌,一开始左手是空的,接着右手开始从桌上摸牌,并将其插入到左手的一把牌中的正确位置上.为了找到这个正确位置,我们需要从右到左将它与手中的牌比较,直到找到合适的位置插入.整个过程的特点是,左手的牌是排好序的了. 详见: 插入排序 二.选择排序:不稳定,时间复杂度O(n^2) 每趟从未排序部分选出最小的元素,然后通过交换将其添加到已排序部分中. 详见: 选择排序 三.冒泡排序:稳定,时间复杂度O(n^2) 将待排序的元素看作是竖着排列的"气泡