带你了解Java数据结构和算法之高级排序

目录
  • 1、希尔排序
    • ①、直接插入排序
    • ②、希尔排序图解
    • ③、排序间隔选取
    • ④、knuth间隔序列的希尔排序算法实现
    • ⑤、间隔为2h的希尔排序
  • 2、快速排序
    • ①、快速排序的基本思路
    • ②、快速排序的算法实现
    • ③、快速排序图示
    • ④、快速排序完整代码
    • ⑤、优化分析
  • 总结

1、希尔排序

希尔排序是基于直接插入排序的,它在直接插入排序中增加了一个新特性,大大的提高了插入排序的执行效率。所以在讲解希尔排序之前,我们先回顾一下直接插入排序。

①、直接插入排序

直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。

实现代码为:

package com.ys.sort;

public class InsertSort {
    public static int[] sort(int[] array){
        int j;
        //从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
        for(int i = 1 ; i < array.length ; i++){
            int tmp = array[i];//记录要插入的数据
            j = i;
            while(j > 0 && tmp < array[j-1]){//从已经排序的序列最右边的开始比较,找到比其小的数
                array[j] = array[j-1];//向后挪动
                j--;
            }
            array[j] = tmp;//存在比其小的数,插入
        }
        return array;
    }

}

我们可以分析一下这个直接插入排序,首先我们将需要插入的数放在一个临时变量中,这也是一个标记符,标记符左边的数是已经排好序的,标记符右边的数是需要排序的。接着将标记的数和左边排好序的数进行比较,假如比目标数大则将左边排好序的数向右边移动一位,直到找到比其小的位置进行插入。

这里就存在一个效率问题了,如果一个很小的数在很靠近右边的位置,比如上图右边待排序的数据 1 ,那么想让这个很小的数 1 插入到左边排好序的位置,那么左边排好序的数据项都必须向右移动一位,这个步骤就是将近执行了N次复制,虽然不是每个数据项都必须移动N个位置,但是每个数据项平均移动了N/2次,总共就是N2/2,因此插入排序的效率是O(N2)。

那么如果以某种方式不必一个一个移动中间所有的数据项,就能把较小的数据项移动到左边,那么这个算法的执行效率会有很大的改进。

②、希尔排序图解

希尔排序应运而生了,希尔排序通过加大插入排序中元素的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项能够大跨度的移动。当这些数据项排过一趟序后,希尔排序算法减小数据项的间隔再进行排序,依次进行下去,最后间隔为1时,就是我们上面说的简单的直接插入排序。

下图显示了增量为4时对包含10个数组元素进行排序的第一个步骤,首先对下标为 0,4,8 的元素进行排序,完成排序之后,算法右移一步,对 1,5,9 号元素进行排序,依次类推,直到所有的元素完成一趟排序,也就是说间隔为4的元素都已经排列有序。

当我们完成4-增量排序之后,在进行普通的插入排序,即1-增量排序,会比前面直接执行简单插入排序要快很多。

③、排序间隔选取

对于10个元素,我们选取4的间隔,那么100个数据,1000个数据,甚至更多的数据,我们应该怎么选取间隔呢?

希尔的原稿中,他建议间隔选为N/2,也就是每一趟都将排序分为两半,因此对于N=100的数组,逐渐减小的间隔序列为:50,25,12,6,3,1。这个方法的好处是不需要在开始排序前为找到初始序列的间隔而计算序列,只需要用2整除N。但是这已经被证明并不是最好的序列。

间隔序列中的数字互质是很重要的指标,也就是说,除了1,他们没有公约数。这个约束条件使得每一趟排序更有可能保持前一趟排序已经排好的结果,而希尔最初以N/2的间隔的低效性就是没有遵守这个准则。

所以一种希尔的变形方法是用2.2来整除每一个间隔,对于n=100的数组,会产生序列45,20,9,4,1。这比用2会整除会显著的改善排序效果。

还有一种很常用的间隔序列:knuth 间隔序列 3h+1

但是无论是什么间隔序列,最后必须满足一个条件,就是逐渐减小的间隔最后一定要等于1,因此最后一趟排序一定是简单的插入排序。

下面我们通过knuth间隔序列来实现希尔排序:

④、knuth间隔序列的希尔排序算法实现

//希尔排序 knuth 间隔序列 3h+1
public static void shellKnuthSort(int[] array){
    System.out.println("原数组为"+Arrays.toString(array));
    int step = 1 ;
    int len = array.length;
    while(step <= len/3){
        step = step*3 + 1;//1,4,13,40......
    }
    while(step > 0){
        //分别对每个增量间隔进行排序
        for(int i = step ; i < len ; i++){
            int temp = array[i];
            int j = i;
            while(j > step-1 && temp <= array[j-step]){
                array[j] = array[j-step];
                j -= step;
            }
            array[j] = temp;
        }//end for
        System.out.println("间隔为"+step+"的排序结果为"+Arrays.toString(array));
        step = (step-1)/3;
    }//end while(step>0)

    System.out.println("最终排序:"+Arrays.toString(array));
}

测试结果:

public static void main(String[] args) {
    int[] array = {4,2,8,9,5,7,6,1,3,10};
    shellKnuthSort(array);
}

⑤、间隔为2h的希尔排序

//希尔排序 间隔序列2h
public static void shellSort(int[] array){
    System.out.println("原数组为"+Arrays.toString(array));
    int step;
    int len = array.length;
    for(step = len/2 ;step > 0 ; step /= 2){
        //分别对每个增量间隔进行排序
        for(int i = step ; i < array.length ; i++){
            int j = i;
            int temp = array[j];
            if(array[j] < array[j-step]){
                while(j-step >=0 && temp < array[j-step]){
                    array[j] = array[j-step];
                    j -= step;
                }
                array[j] = temp;
            }
        }
        System.out.println("间隔为"+step+"的排序结果为"+Arrays.toString(array));
    }
}

测试结果:

  

2、快速排序

快速排序是对冒泡排序的一种改进,由C. A. R. Hoare在1962年提出的一种划分交换排序,采用的是分治策略(一般与递归结合使用),以减少排序过程中的比较次数。

①、快速排序的基本思路

一、先通过第一趟排序,将数组原地划分为两部分,其中一部分的所有数据都小于另一部分的所有数据。原数组被划分为2份

二、通过递归的处理, 再对原数组分割的两部分分别划分为两部分,同样是使得其中一部分的所有数据都小于另一部分的所有数据。 这个时候原数组被划分为了4份

三、就1,2被划分后的最小单元子数组来看,它们仍然是无序的,但是!它们所组成的原数组却逐渐向有序的方向前进。

四、这样不断划分到最后,数组就被划分为多个由一个元素或多个相同元素组成的单元,这样数组就有序了。

具体实例:

对于上图的数组[3,1,4,1,5,9,2,6,5,3],通过第一趟排序将数组分成了[2,1,1]或[4,5,9,3,6,5,3]两个子数组,且对于任意元素,左边子数组总是小于右边子数组。通过不断的递归处理,最终得到有序数组[1 1 2 3 3 4 5 5 6]

②、快速排序的算法实现

假设被排序的无序区间为[A[i],......,A[j]]

一、基准元素选取:选择其中的一个记录的关键字 v 作为基准元素(控制关键字);怎么选取关键字?

二、划分:通过基准元素 v 把无序区间 A[I]......A[j] 划分为左右两部分,使得左边的各记录的关键字都小于 v;右边的各记录的关键字都大于等于 v;(如何划分?)

三、递归求解:重复上面的一、二步骤,分别对左边和右边两部分递归进行快速排序。

四、组合:左、右两部分均有序,那么整个序列都有序。

上面的第 三、四步不用多说,主要是第一步怎么选取关键字,从而实现第二步的划分?

划分的过程涉及到三个关键字:“基准元素”、“左游标”、“右游标”

基准元素:它是将数组划分为两个子数组的过程中,用于界定大小的值,以它为判断标准,将小于它的数组元素“划分”到一个“小数值的数组”中,而将大于它的数组元素“划分”到一个“大数值的数组”中,这样,我们就将数组分割为两个子数组,而其中一个子数组的元素恒小于另一个子数组里的元素。

左游标:它一开始指向待分割数组最左侧的数组元素,在排序的过程中,它将向右移动。

右游标:它一开始指向待分割数组最右侧的数组元素,在排序的过程中,它将向左移动。

注意:上面描述的基准元素/右游标/左游标都是针对单趟排序过程的, 也就是说,在整体排序过程的多趟排序中,各趟排序取得的基准元素/右游标/左游标一般都是不同的。

对于基准元素的选取,原则上是任意的。但是一般我们选取数组中第一个元素为基准元素(假设数组是随机分布的)

③、快速排序图示

上面表示的是一个无序数组,选取第一个元素 6 作为基准元素。左游标是 i 哨兵,右游标是 j 哨兵。然后左游标向左移动,右游标向右移动,它们遵循的规则如下:

一、左游标向右扫描,跨过所有小于基准元素的数组元素,直到遇到一个大于或等于基准元素的数组元素, 在那个位置停下。

二、右游标向左扫描,跨过所有大于基准元素的数组元素,直到遇到一个小于或等于基准元素的数组元素,在那个位置停下。

第一步:哨兵 j 先开始出动。因为此处设置的基准数是最左边的数,所以需要让哨兵 j 先开始出动,哨兵 j 一步一步的向左挪动,直到找到一个小于 6 的元素停下来。接下来,哨兵 i 再一步一步的向右挪动,直到找到一个大于 6 的元素停下来。最后哨兵 i 停在了数字 7 面前,哨兵 j 停在了数字 5 面前。

到此,第一次交换结束,接着哨兵 j 继续向左移动,它发现 4 比基准数 6 要小,那么在数字4面前停下来。哨兵 i 也接着向右移动,然后在数字 9 面前停下来,然后哨兵 i 和 哨兵 j 再次进行交换。

第二次交换结束,哨兵 j 继续向左移动,然后在数字 3 面前停下来;哨兵 i 继续向右移动,但是它发现和哨兵 j 相遇了。那么此时说明探测结束,将数字 3 和基准数字 6 进行交换,如下:

到此,第一次探测真正结束,此时已基准点 6 为分界线,6 左边的数组元素都小于等于6,6右边的数组元素都大于等于6。

左边序列为【3,1,2,5,4】,右边序列为【9,7,10,8】。接着对于左边序列而言,以数字 3 为基准元素,重复上面的探测操作,探测完毕之后的序列为【2,1,3,5,4】;对于右边序列而言,以数字 9 位基准元素,也重复上面的探测操作。然后一步一步的划分,最后排序完全结束。

通过这一步一步的分解,我们发现快速排序的每一轮操作就是将基准数字归位,知道所有的数都归位完成,排序就结束了。

④、快速排序完整代码

package com.ys.high.sort;

public class QuickSort {

    //数组array中下标为i和j位置的元素进行交换
    private static void swap(int[] array , int i , int j){
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    private static void recQuickSort(int[] array,int left,int right){
        if(right <= left){
            return;//终止递归
        }else{

            int partition = partitionIt(array,left,right);
            recQuickSort(array,left,partition-1);// 对上一轮排序(切分)时,基准元素左边的子数组进行递归
            recQuickSort(array,partition+1,right);// 对上一轮排序(切分)时,基准元素右边的子数组进行递归
        }
    }

    private static int partitionIt(int[] array,int left,int right){
        //为什么 j加一个1,而i没有加1,是因为下面的循环判断是从--j和++i开始的.
        //而基准元素选的array[left],即第一个元素,所以左游标从第二个元素开始比较
        int i = left;
        int j = right+1;
        int pivot = array[left];// pivot 为选取的基准元素(头元素)
        while(true){
            while(i<right && array[++i] < pivot){}

            while(j > 0 && array[--j] > pivot){}

            if(i >= j){// 左右游标相遇时候停止, 所以跳出外部while循环
                break;
            }else{
                swap(array, i, j);// 左右游标未相遇时停止, 交换各自所指元素,循环继续
            }
        }
        swap(array, left, j);//基准元素和游标相遇时所指元素交换,为最后一次交换
        return j;// 一趟排序完成, 返回基准元素位置(注意这里基准元素已经交换位置了)
    }

    public static void sort(int[] array){
        recQuickSort(array, 0, array.length-1);
    }

    //测试
    public static void main(String[] args) {
        //int[] array = {7,3,5,2,9,8,6,1,4,7};
        int[] array = {9,9,8,7,6,5,4,3,2,1};
        sort(array);
        for(int i : array){
            System.out.print(i+" ");
        }
        //打印结果为:1 2 3 4 5 6 7 7 8 9
    }
}

⑤、优化分析

假设我们是对一个逆序数组进行排序,选取第一个元素作为基准点,即最大的元素是基准点,那么第一次循环,左游标要执行到最右边,而右游标执行一次,然后两者进行交换。这也会划分成很多的子数组。

那么怎么解决呢?理想状态下,应该选择被排序数组的中值数据作为基准,也就是说一半的数大于基准数,一般的数小于基准数,这样会使得数组被划分为两个大小相等的子数组,对快速排序来说,拥有两个大小相等的子数组是最优的情况。

三项取中划分

为了找到一个数组中的中值数据,一般是取数组中第一个、中间的、最后一个,选择这三个数中位于中间的数。

//取数组下标第一个数、中间的数、最后一个数的中间值
private static int medianOf3(int[] array,int left,int right){
    int center = (right-left)/2+left;
    if(array[left] > array[right]){ //得到 array[left] < array[right]
        swap(array, left, right);
    }
    if(array[center] > array[right]){ //得到 array[left] array[center] < array[right]
        swap(array, center, right);
    }
    if(array[center] > array[left]){ //得到 array[center] <  array[left] < array[right]
        swap(array, center, left);
    }

    return array[left]; //array[left]的值已经被换成三数中的中位数, 将其返回
}
private static int partitionIt(int[] array,int left,int right){
    //为什么 j加一个1,而i没有加1,是因为下面的循环判断是从--j和++i开始的.
    //而基准元素选的array[left],即第一个元素,所以左游标从第二个元素开始比较
    int i = left;
    int j = right+1;
    int pivot = array[left];// pivot 为选取的基准元素(头元素)

    int size = right - left + 1;
    if(size >= 3){
        pivot = medianOf3(array, left, right); //数组范围大于3,基准元素选择中间值。
    }
    while(true){
        while(i<right && array[++i] < pivot){}

        while(j > 0 && array[--j] > pivot){}

        if(i >= j){// 左右游标相遇时候停止, 所以跳出外部while循环
            break;
        }else{
            swap(array, i, j);// 左右游标未相遇时停止, 交换各自所指元素,循环继续
        }
    }
    swap(array, left, j);//基准元素和游标相遇时所指元素交换,为最后一次交换
    return j;// 一趟排序完成, 返回基准元素位置(注意这里基准元素已经交换位置了)
}

处理小划分

如果使用三数据取中划分方法,则必须遵循快速排序算法不能执行三个或者少于三个的数据,如果大量的子数组都小于3个,那么使用快速排序是比较耗时的。联想到前面我们讲过简单的排序(冒泡、选择、插入)。

当数组长度小于M的时候(high-low <= M), 不进行快排,而进行插入排序。转换参数M的最佳值和系统是相关的,一般来说, 5到15间的任意值在多数情况下都能令人满意。

//插入排序
private static void insertSort(int[] array){
    for(int i = 1 ; i < array.length ; i++){
        int temp = array[i];
        int j = i;
        while(j > 0 && array[j-1] > temp){
            array[j] = array[j-1];
            j--;
        }
        array[j] = temp;
    }
}

PS:这里写一下归并排序的算法

public static void testMergeSort(){
    int[] array = {4,2,9,8,1,6,3,5,7};

    mergeSort(array,0,array.length-1);
    System.out.println(array);
}

public static void mergeSort(int[] array,int left,int right){
    if(left < right){
        int mid = left + (right-left)/2;
        //对左边数组进行排序
        mergeSort(array,left,mid);
        //对右边数据进行排序
        mergeSort(array,mid+1,right);
        //合并两边数组
        merge(array,left,mid,right);
    }
}
public static void merge(int[] array,int left,int mid,int right){
    //注意每一次合并申请的临时数组大小是不一样的
    int[] temp = new int[right-left+1];
    //新数组的索引
    int i = 0;
    //需要合并的两个数组起点
    int j = left,k=mid+1;
    // 把较小的数先移到新数组中
    while(j <= mid && k<=right){
        if(array[j] < array[k]){
            temp[i++] = array[j++];
        }else{
            temp[i++] = array[k++];
        }
    }
    // 把左边剩余的数移入数组
    while(j<=mid){
        temp[i++] = array[j++];
    }
    // 把右边边剩余的数移入数组
    while(k<=right){
        temp[i++] = array[k++];
    }
    // 把新数组中的数覆盖array数组
    for (int l = 0; l < temp.length; l++) {
        array[l+left] = temp[l];
    }
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 带你了解Java数据结构和算法之递归

    目录 1.递归的定义 2.求一个数的阶乘:n! 3.递归的二分查找 4.分治算法 5.汉诺塔问题 6.归并排序 7.消除递归 8.递归的有趣应用 ①.求一个数的乘方 ②.背包问题 ③.组合:选择一支队伍 9.总结 1.递归的定义 递归,就是在运行的过程中调用自己. 递归必须要有三个要素: ①.边界条件 ②.递归前进段 ③.递归返回段 当边界条件不满足时,递归前进:当边界条件满足时,递归返回. 2.求一个数的阶乘:n! 规定: ①.0!=1 ②.1!=1 ③.负数没有阶乘 上面的表达式我们先用fo

  • 带你了解Java数据结构和算法之二叉树

    目录 1.树 2.二叉树 3.查找节点 4.插入节点 5.遍历树 6.查找最大值和最小值 7.删除节点 ①.删除没有子节点的节点 ②.删除有一个子节点的节点 ③.删除有两个子节点的节点 ④.删除有必要吗? 8.二叉树的效率 9.用数组表示树 10.完整的BinaryTree代码 11.哈夫曼(Huffman)编码 ①.哈夫曼编码 ②.哈夫曼解码 12.总结 1.树 树(tree)是一种抽象数据类型(ADT),用来模拟具有树状结构性质的数据集合.它是由n(n>0)个有限节点通过连接它们的边组成一个

  • 带你了解Java数据结构和算法之2-3-4树

    目录 1.2-3-4 树介绍 2.搜索2-3-4树 3.插入 1.节点分裂 2.根的分裂 4.完整源码实现 5.2-3-4树和红黑树 ①.对应规则 ②.操作等价 6.2-3-4 树的效率 总结 1.2-3-4 树介绍 2-3-4树每个节点最多有四个字节点和三个数据项,名字中 2,3,4 的数字含义是指一个节点可能含有的子节点的个数.对于非叶节点有三种可能的情况: ①.有一个数据项的节点总是有两个子节点: ②.有二个数据项的节点总是有三个子节点: ③.有三个数据项的节点总是有四个子节点: 简而言之

  • 带你了解Java数据结构和算法之链表

    目录 1.链表(Linked List) 2.单向链表(Single-Linked List) ①.单向链表的具体实现 ②.用单向链表实现栈 4.双端链表 ①.双端链表的具体实现 ②.用双端链表实现队列 5.抽象数据类型(ADT) 6.有序链表 7.有序链表和无序数组组合排序 8.双向链表 9.总结 前面博客我们在讲解数组中,知道数组作为数据存储结构有一定的缺陷.在无序数组中,搜索性能差,在有序数组中,插入效率又很低,而且这两种数组的删除效率都很低,并且数组在创建后,其大小是固定了,设置的过大会

  • 深入了解Java数据结构和算法之堆

    目录 1.堆的定义 2.遍历和查找 3.移除 4.插入 5.完整的Java堆代码 总结 1.堆的定义 ①.它是完全二叉树,除了树的最后一层节点不需要是满的,其它的每一层从左到右都是满的.注意下面两种情况,第二种最后一层从左到右中间有断隔,那么也是不完全二叉树. ②.它通常用数组来实现. 这种用数组实现的二叉树,假设节点的索引值为index,那么: 节点的左子节点是 2*index+1, 节点的右子节点是 2*index+2, 节点的父节点是 (index-1)/2. ③.堆中的每一个节点的关键字

  • 带你了解Java数据结构和算法之哈希表

    目录 1.哈希函数的引入 ①.把数字相加 ②.幂的连乘 2.冲突 3.开放地址法 ①.线性探测 ②.装填因子 ③.二次探测 ④.再哈希法 4.链地址法 5.桶 6.总结 1.哈希函数的引入 大家都用过字典,字典的优点是我们可以通过前面的目录快速定位到所要查找的单词.如果我们想把一本英文字典的每个单词,从 a 到 zyzzyva(这是牛津字典的最后一个单词),都写入计算机内存,以便快速读写,那么哈希表是个不错的选择. 这里我们将范围缩小点,比如想在内存中存储5000个英文单词.我们可能想到每个单词

  • 带你了解Java数据结构和算法之高级排序

    目录 1.希尔排序 ①.直接插入排序 ②.希尔排序图解 ③.排序间隔选取 ④.knuth间隔序列的希尔排序算法实现 ⑤.间隔为2h的希尔排序 2.快速排序 ①.快速排序的基本思路 ②.快速排序的算法实现 ③.快速排序图示 ④.快速排序完整代码 ⑤.优化分析 总结 1.希尔排序 希尔排序是基于直接插入排序的,它在直接插入排序中增加了一个新特性,大大的提高了插入排序的执行效率.所以在讲解希尔排序之前,我们先回顾一下直接插入排序. ①.直接插入排序 直接插入排序基本思想是每一步将一个待排序的记录,插入

  • java数据结构与算法之希尔排序详解

    本文实例讲述了java数据结构与算法之希尔排序.分享给大家供大家参考,具体如下: 这里要介绍的是希尔排序(缩小增量排序法). 希尔排序:通过比较相距一定间隔的元素来工作:各趟比较所用的距离(增量)随着算法的进行而减小,直到只比较相邻元素的最后一趟排序为止.是插入排序的一种,是针对直接插入排序算法的改进. 算法思想:先将要排序的序列按某个增量d分成若干个子序列,对每个子序列中全部元素分别进行直接插入排序,然后再用一个较小的增量对它进行分组,在每组中再进行排序.当增量减到1时,整个要排序的数被分成一

  • java数据结构与算法之桶排序实现方法详解

    本文实例讲述了java数据结构与算法之桶排序实现方法.分享给大家供大家参考,具体如下: 基本思想: 假定输入是由一个随机过程产生的[0, M)区间上均匀分布的实数.将区间[0, M)划分为n个大小相等的子区间(桶),将n个输入元素分配到这些桶中,对桶中元素进行排序,然后依次连接桶输入0 ≤A[1..n] <M辅助数组B[0..n-1]是一指针数组,指向桶(链表).将n个记录分布到各个桶中去.如果有多于一个记录分到同一个桶中,需要进行桶内排序.最后依次把各个桶中的记录列出来记得到有序序列. [桶-

  • Java数据结构与算法之选择排序(动力节点java学院整理)

    每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完. 代码 public class ChoseSort { //constructor without parameters public ChoseSort(){}; //constructor with parameters public int[] ChoseSort(int[] intArr){ for(int i=0;i<intArr.length-1;i++){ int

  • java数据结构与算法之奇偶排序算法完整示例

    本文实例讲述了java数据结构与算法之奇偶排序算法.分享给大家供大家参考,具体如下: 算法思想: 基本思路是奇数列排一趟序,偶数列排一趟序,再奇数排,再偶数排,直到全部有序 举例吧, 待排数组[6 2 4 1 5 9] 第一次比较奇数列,奇数列与它的邻居偶数列比较,如6和2比,4和1比,5和9比 [6 2 4 1 5 9] 交换后变成 [2 6 1 4 5 9] 第二次比较偶数列,即6和1比,5和5比 [2 6 1 4 5 9] 交换后变成 [2 1 6 4 5 9] 第三趟又是奇数列,选择的是

  • 带你了解Java数据结构和算法之栈

    目录 1.栈的基本概念 2.Java模拟简单的顺序栈实现 3.增强功能版栈 4.利用栈实现字符串逆序 5.利用栈判断分隔符是否匹配 6.总结 1.栈的基本概念 栈(英语:stack)又称为堆栈或堆叠,栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针. 栈是允许在同一端进行插入和删除操

  • 带你了解Java数据结构和算法之数组

    目录 1.Java数组介绍 ①.数组的声明 ②.访问数组元素以及给数组元素赋值 ③.数组遍历 2.用类封装数组实现数据结构 3.分析数组的局限性 4.总结 1.Java数组介绍 在Java中,数组是用来存放同一种数据类型的集合,注意只能存放同一种数据类型(Object类型数组除外). ①.数组的声明 第一种方式: 数据类型 [] 数组名称 = new 数据类型[数组长度]; 这里 [] 可以放在数组名称的前面,也可以放在数组名称的后面,我们推荐放在数组名称的前面,这样看上去 数据类型 [] 表示

  • 带你了解Java数据结构和算法之无权无向图

    目录 1.图的定义 ①.邻接: ②.路径: ③.连通图和非连通图: ④.有向图和无向图: ⑤.有权图和无权图: 2.在程序中表示图 ①.顶点: ②.边: 3.搜索 ①.深度优先搜索(DFS) ②.广度优先搜索(BFS) ③.程序实现 4.最小生成树 5.总结 1.图的定义 我们知道,前面讨论的数据结构都有一个框架,而这个框架是由相应的算法实现的,比如二叉树搜索树,左子树上所有结点的值均小于它的根结点的值,右子树所有结点的值均大于它的根节点的值,类似这种形状使得它容易搜索数据和插入数据,树的边表示

随机推荐