《啊哈!算法》阅读笔记-----第一章《排序》

这学期课格外少,最怕闲着。所以近期开始读《啊哈!算法》,听说是适合大一新生看的书,但我挺喜欢好理解的书的。那么我的阅读就此开始啦。


  • 第一章—-排序
  • 第一节—-桶排序
    把数据抽象成桶,桶的底层则是数组,若数据是:1,4,6,7,8.那我们就需要一个长度为9的数组(下标从0~8)。数据的呈现方式是通过下标对应的值。例如array[0]=0,array[1]=1,arrar[2]=0….拿下标对应的数组的值来代表数据出现的次数。
    eg:将2,6,3,6,9用桶排序按照从小到大顺序排序输出。
public static void mian(String[] args){
Scanner sc = new Scanner(System.in);
//定义长度为10的数组
int[] array = new int[10];
//初始化
for(int i = 0 ;i < 10; i++){
    array[i] = 0;
}
//循环读入所有数据
for(int i = 0; i < 5;i++){
  int x = sc.nextInt();
  array[x]++;
}
//循环遍历数组并打印输出
for(int i = 0;i < 10;i++){
    for(int j = 1;j<=array[i];j++){
    System.out.print(array[i]);
    }
}
}

以上只是简易版的桶排序,但代码部分还有问题。
桶排序的时间复杂度:O(M+N) M:桶的个数 N:待排序数的个数
桶排序的优点:快速、简单
桶排序的缺点:当数据取值范围很大,但需要排序的数据却很少时,十分浪费空间


  • 第二节—-冒泡排序
    冒泡排序是我们学习的第一个排序算法,所以记忆特别深刻。
    由于桶排序的浪费空间以及得到的结果形式不尽人意的缺点,我们需要学习能有效解决这两种问题的一种新的排序—冒泡排序。
    冒泡排序的思想是:每次比较俩个相邻的元素,若有顺序问题则交换。需要注意的是,一趟冒泡排序只能将序列中一个数归位,并且归位到了序列的后部分。

若有n个数需要进行冒泡排序,则需要进行n-1趟排序。同时还要注意,每趟排序并不是从前到后所有数据都要比较,后部分已经归位的数就不用再比较了。

重点代码如下:

for(int i = 0 ; i < n;i++){
    for(int j = 0;j < n-i ;j++){
        if(array[j]<array[j+1]){
            temp = array[j];
            array[j] = array[j+1];
            array[j+1] = temp;
    }
    }
}

冒泡排序的时间复杂度:O(N^2) —-很费时。


  • 快速排序
    虽说冒泡排序解决了刚开始的桶排序的浪费空间的问题,但是冒泡排序也有自身的问题——算法执行效率低。所以我们又要来了解一个很美的快排—–既不浪费空间又保证快速的排序算法。
    在这本书里面,对快速排序的算法描述和我大二学习数据结构时候学习的快排的算法描述有一点点的不同,但本质都是一样的。现在我觉得这本书的描述更加清晰好理解。下面我来回顾一下这本书里面的描述:
    1.首先对于一个数据序列,我们定首元为哨兵i,末元为哨兵j。
    2.将哨兵i当作基准,让哨兵j先开始动。怎么动呢?从后往前一个一个动啦,直到遇到比基准值小的值就停止在当前位置。
    3.接下来该哨兵i动。i从前往后动,直到遇到比基准值大的就停在当前位置。
    4.哨兵ij都找好位置之后,交换ij里面的值。
    5.交换完之后,哨兵ij从当前位置出发,继续按照基准来找。注意还是哨兵j先开始找。
    6.直到哨兵ij相遇在一个位置,就把当前位置的值赋给首元位置,再把基准值给放到当前相遇的位置。一趟快排就算结束了。

当然以上的描述只是一趟快排的过程,已经归位的基准值将序列分成了两部分,我们需要二分的思想继续左右两部分继续快排。

快排为什么比冒泡排序快呢?
主要是因为快排的交换是跳跃的,而冒泡排序是相邻元素之间的比较和交换。

重点代码(c语言):

int array[100]; //定义全局数组
int main(){
    int i,j;
    scanf("%d",&n);
    for(i = 1;i <= n;i++)
        sacnf("%d",&array[i]);
    QuickSort(1,n); //调用快排函数,注意这里的参数是数组下标,
                    //因为哨兵i和哨兵j接下来进行操作时都是用索引来比较。

    //打印快排后的数组省略代码
}

void QuickSort(int left,int right){
    int i,j,temp;
    if(left>right) //传来的数组下标非法,直接退出
        return;
    temp = array[left]; //将首元的值存进基准值变量temp
    i = left;
    j = right;

    while(i != j){
    //当数据大于等于基准值时,哨兵j直接前移
        while(array[j]>=temp && i<j){
            j--;
        }
    //当数据大于等于基准值时,哨兵j直接前移
        while(array[i]<=temp && i<j){
            i++;
        }
    //当俩这都停止移动并且i<j时,交换值
        if(i<j){
            t = array[i];
            array[i] = array[j];
            array[j] = t;
        }
    }
    //当俩者相遇在同一位置时,将当前位置值和基准值互换
    a[left] = a[i];
    a[i] = temp;

    //二分思想继续快排
    QuickSort(left,i-1);
    QuickSort(i+1,right);
    return;
}

快速排序的最差时间复杂度和冒泡排序一样都是O(N^2),平均时间复杂度是O(NlogN)
过几天补上这里差的一个小demo,现在先去开始第二张知识点啦~

猜你喜欢

转载自blog.csdn.net/qq_39091292/article/details/82350633
今日推荐