【JAVA数据结构】Java排序(七大排序 + 动图代码解析)

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 排序有很多种,一般以主流升序或者降序为主(不包含特殊的排序序列)【这里讲解都是升序且是整形,其他类型以此类推,改个符号和比较方法就好】

JAVA数据结构 & Java排序(七大排序 + 动图代码解析)

排序有很多种,一般以主流升序或者降序为主(不包含特殊的排序序列)【这里讲解都是升序且是整形,其他类型以此类推,改个符号和比较方法就好】


排序在很多场景下特别场景,例如淘宝的各种排序列表,高效的排序在这里显得尤为重要,所以在讲解排序时,会结合复杂度的分析


对于链表的排序我建议用归并


下列这个图只是思想上的分类罢了



排序是否稳定:在于相同的元素是否被交换了先后位置


七大排序之中,只有《直接插入排序》《冒泡排序》《归并排序》是 稳定的。


1. 插入排序


大家可以多看几次动图,这样理解起来会更好


没错,如你所见,插入排序就是,下标从左往右走,没次将对应下标的元素往前插入到合适的位置(不一定是最终位置),然后大于他的就往后挪,(挪的方法一定是从尾巴往后,这样就不会影响其他值)


始终都有个位置留给这个值,不管是否需要挪动
    /**
     * 插入排序
     * @param arr
     */
   //时间 O(N^2)  最好的情况是O(N)  数据接近有序,建议插入排序
    // 空间 O(1)
    //是稳定的 ,稳定是可以实现为不稳定
    // 但是不稳定是不可实现为稳定的
    public static void insertSort(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);//这一步只是堆数组进行拷贝(引用类型记得设计为深拷贝哦!)
        //目的是为了不改变原数组,方便多组测试
        for (int i = 1; i < arr.length; i++) {
            int tmp = arr[i];
            int j = i - 1;
          //挪动数据
            for(; j >= 0 && arr[j] > tmp; j--) {
                arr[j + 1] = arr[j];
            }
            //插入空地里
            arr[j + 1] = tmp;
        }
        //可以在这里sout打印一下
    }



2. 希尔排序


大家可以多看几次动图,这样理解起来会更好,并且一定要结合插入排序的思想!


总体来说,这个排序在插入排序的基础上,增加了“随机性”-–>就是让后面排在前面的数据,有更大的机会提前排好,减少极端条件下,数据被挪动很多次!但是也因此失去了【稳定性】


这里有一个很重要的变量【gap,间隔】,每次间隔都会变小,其实插入排序的间隔是1,这里希尔排序的间隔从大到小,实际上就是"跳着比较,跳着挪",当gap == 1时,退化成希尔排序,但是希尔排序,越有序越快!


/**
     * 希尔排序
     * 时间复杂度 O(N^1.3) - O(N^1.5),至今还未能精确算出!
     * 空间复杂度 O(1)
     * 【不稳定】排序
     * @param arr
     */
//一趟一趟的排!
    public static void shellSort(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        int gap = arr.length / 2;
        while(gap >= 1) {
            shell(arr, gap);
            gap /= 2;
        }
    }
//一趟希尔排序的希尔方法 -----》无非就是插入排序的 1 --> gap
    public static void shell(int[] arr, int gap) {
        for (int i = gap; i < arr.length; i++) {
            int j = i - gap;
            int tmp = arr[i];
            while(j >= 0) {
                if(arr[j] > tmp) {
                    arr[j + gap] = arr[j];
                }else {
                    break;
                }
                j -= gap;
            }
            arr[j + gap] = tmp;
        }
    }



3. 选择排序


大家可以多看几次动图,这样理解起来会更好


由于选择排序有交换的情节,在一趟选择,如果一个元素比当前元素小,而**该小的元素又出现在一个和当前元素相等的元素后面, 那么交换后稳定性就被破坏了。


不难看出,每趟排序,都在往后(对应局部空间,不包含已排好部分)选择最小值进行交换,每次都能确定一个元素的最终位置


/**
     * 选择排序
     * 时间复杂度 O(N^2)
     * 空间复杂度 O(1)
     * 【不稳定】
     * @param arr
     */
    public static void selectSort1(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        for (int i = 0; i < arr.length; i++) {
            int minIndex = i;
            for (int j = i; j < arr.length; j++) {
                if(arr[minIndex] > arr[j]) {
                    minIndex = j;
                }
            }
            if(i != minIndex) {
                int tmp = arr[minIndex];
                arr[minIndex] = arr[i];
                arr[i] = tmp;
            }
        }
    }


4. 堆排序


一定要学习堆知识后再学习这个排序!


用到的原理无非就是,建立大根堆,堆顶元素删除时会被放在【末尾】,就是说最大元素每次都被插都后面,确定最终位置!


由于堆对应的结构是完全二叉树,所以这种排序效率上不会因为数据怎么样而变化很大。


/**
     * 堆排序
     * 时间复杂度为 O(N*log2N)   N*logN + N ----> N*logN(取最高阶)
     * 空间复杂度为 O(1);
     * 【不稳定】(排在前面的相同元素会更快的被查到后面)
     * @param arr
     */
//一趟一趟排
    public static void heapSort(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);//方便测试,这条语句去掉就是O(1)
        createHeap(arr);
        for (int end = arr.length - 1; end >= 0; end--) {
            //将堆顶与【末尾】交换,
            int tmp = arr[0];
            arr[0] = arr[end];
            arr[end] = tmp;
            //并且保证刚才那个之前的那一部分仍是大根堆
            shiftDown(arr, 0, end - 1);
        }
    }
//每次都要向下调整(向下调整一次就好,向上可能要很多次,这里参考堆的知识),保证还是大根堆!
  private static void shiftDown(int[] arr, int parent, int len) {
        int child = 2 * parent + 1;
        while(child <= len) {
            if(child + 1 <= len && arr[child + 1] > arr[child]) {
                child++;
            }
            if(arr[child] > arr[parent]) {
                int tmp = arr[child];
                arr[child] = arr[parent];
                arr[parent] = tmp;
                parent = child;
                child = 2 * parent + 1;
            }else {
                break;
            }
        }
    }
//建立大根堆方法!向下调整的构造法,节省大量时间!
    private static void createHeap(int[] arr) {
        for (int i = (arr.length - 2) / 2; i >= 0; i--) {
            shiftDown(arr, i, arr.length - 1);
        }
    }



5. 冒泡排序


大家可以多看几次动图,这样理解起来会更好


不难看出,每趟排序都能将最大的值传到最后(确定最终位置),一旦判断到相邻元素 左>右 就会交换


每次交换都纠正了两个元素的宏观相对位置


一趟排序确定一个,那么那一个就不需要参与下一趟排序


最后一趟排序只有一个元素,可以忽略


确定有序就结束


/**
     * 冒泡排序
     * 时间复杂度(不考虑优化) O(N^2)
     * 空间复杂度 O(1)
     *
     * 【稳定】
     * @param arr
     */
    public static void bubbleSort(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        for (int i = 0; i < arr.length; i++) {
            boolean flag = true;
            for (int j = 1; j < arr.length - i; j++) {
                if(arr[j - 1] > arr[j]) {
                    flag = false;
                    int tmp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = tmp;
                }
            }
            if(flag) {
                return;// --->排好就收!
            }
        }
    }


6. 快速排序


大家可以多看几次动图,这样理解起来会更好,现在理解不了没关系,请观看后面的解释,加强理解,再回头看这个动图


(了解,不了解都无所谓)如果你学习到了二叉搜索树,不难看出他在逻辑上是数组型的二叉搜索树


重点在于一个变量【pivot,基准值】----这个值作为分界点,左边都比它小,右边都比它大


我们需要挪动pivot,在这个过程中解决左右值的问题


6.1 基准的确定

对于基准值,一味的用第一个元素,若遇到极端情况下(排好的正序or逆序),排序速度会很慢, 因为这种情况下基准值确定位置后,仅仅往后移了一位,相当于每趟确定左值为最小(或者右值最大),相当于退化成冒泡排序了。

上面这种情况下,甚至会栈溢出!因为一些方法栈帧没有销毁,又有新的栈帧了。

下面是优化方案:三值取中法

这样可以保证基准确定位置后,趋中

确认基准值之后,应该将其放在【头】,这样左右下标就可以走遍整个序列啦

private static int findMid(int[] arr, int left, int right) {
        int mid = (left + right) >>> 1;
        if(arr[left] < right) {
            if(arr[mid] < arr[left]) {
                return left;
            }else if(arr[mid] > arr[right]) {
                return right;
            }else {
                return mid;
            }
        }else {
            if(arr[mid] > arr[right]) {
                return right;
            }else if(arr[mid] < arr[left]) {
                return left;
            }else {
                return mid;
            }
        }
    }



6.2 临近末尾

快速排序一般用于排序海量数据,排序很多趟之后,其实一段序列基本有序了,所以可以采取插入排序可以增加速率


思想: 快速排序可以快速排序很乱的序列(不是逆序,而是乱),再用插入排序解决序列较有序的序列,大大提高效率


下面是优化方案:


private static final int QUIT_METHOD = 50;
    //优化2---->减少后面的递归,因为在很多次的找pivot后,其实会变得很有序,那么这个时候用插入排序会很快解决问题
    private static void insertLittleSort(int arr[], int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            int tmp = arr[i];
            int j = i - 1;
            for(; j >= 0 && arr[j] > tmp; j--) {
                arr[j + 1] = arr[j];
            }
            arr[j + 1] = tmp;
        }
    }


6.3 三种基准调整方法:

6.3.1挖坑法:


多看几次动图!这种方法比较随意,这里在首元素的【坑】最先填上,然后替换的原位置成为新的坑

//挖坑法
    private static int partition1(int[] arr, int left, int right) {
        int tmp = arr[left];
        while(left < right) {
            while(left < right && arr[right] >= tmp) { 
                //等号两个都不取的话,那么就会死循环
                right--;
            }
            arr[left] = arr[right];//left为刚才的坑
            while(left < right && arr[left] <= tmp) {
                //也就是说不能出现同一条件,两边都能填的情况,都加上等号,这样写好看
                left++;
            }
            arr[right] = arr[left];//right为刚才的坑
        }
        //这里先右再左,不然交换后初始点的位置就一定是比pivot大
        arr[left] = tmp;
        return left;
    }


6.3.2 Hoare法(最初)


多看几次动图! 这方法一开始基准最后再与相遇时下标对应的元素交换

//Hoare法
    private static int partition2(int[] arr, int left, int right) {
        int index = left;
        while(left < right) {
            while(left < right && arr[right] >= arr[index]) {
                right--;
            }
            while(left < right && arr[left] <= arr[index]) {
                left++;
            }
            int tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
        }
        //这里要右开始是因为要保证,left相遇的时候是总是较小值,所以根初始点的值交换
        int tmp = arr[index];
        arr[index] = arr[left];
        arr[left] = tmp;
        return left;
    }


6.3.3 前后下标指针法(了解即可)


多看几次动图! 这种方法保证了prev后面不存在小于基准值的元素!

//前后指针法
    private static int partition3(int[] arr, int left, int right) {
        int prev = left;
        int cur = left + 1;
        while(cur <= right) {
            if(arr[cur] < arr[left] && arr[++prev] != arr[cur]) {
                int tmp = arr[cur];
                arr[cur] = arr[prev];
                arr[prev] = tmp;
            }
        //保证每次往前换之后,prev的前面都是较小值
            cur++;
        }
        int tmp = arr[left];
        arr[left] = arr[prev];
        arr[prev] = tmp;
        return prev;
    }



6.4 递归法代码实现

这里展示的是挖坑法,只需要将方法名改一下就OK了!

要结合递归思想,左边排完看成整体,右边排完看成整体

别忘了递归出口,这里优化后是交给插入排序

/**
     * 快速排序
     * 时间复杂度:O(N*log2N)(最好)  O(N^2)(最坏,正序or逆序)(越有序越慢)
     * 空间复杂度:O(log2N)(最好) O(N)(最坏)
     * 【不稳定】 -----> 因为相同值在交换到对立位置是有先后的,如果不是基准值相同,则很大可能不稳定
     * 并且靠前的相同值会被换到上一个后面的位置
     * @param arr
     */
    public static void quickSort1(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        quick1(arr, 0, arr.length - 1);
    }
private static void quick1(int[] arr, int left, int right) {
        if(left >= right) {
            return;
        }
        int index = findMid(arr, left, right);
        if(right - left + 1 <= QUIT_METHOD) {
// QUIT_METHOD小区间时停止递归
            insertLittleSort(arr, left, right);
            return;
        }
        {
//因为我们都是默认从第一个做基准值,所以我们只需要与第一个换一下位置就好了,并且我们是在两端向中的,所以这样最规范最全面合适
            int tmp = arr[index];
            arr[index] = arr[left];
            arr[left] = tmp;
        }
        int pivot = partition1(arr, left, right);
        quick1(arr, left, pivot - 1);
        quick1(arr, pivot + 1, right);
    }



6.5 非递归实现(了解)

6.5.1 栈模拟递归前序遍历

这里一些基础方法与递归使用的是一样的!

栈的先进后出,可以很好的模拟递归的 “归 ”

public static void quickSortNormal1(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        //栈模拟递归
        Deque<Integer> stack = new LinkedList<>();
        //也可以用队列模拟层序遍历,这就不是往模拟递归的方向走了
        //思路是一层完了之后再下一层,直到结束
        int left = 0;
        int right = arr.length - 1;
        do {
            int index = findMid(arr, left, right);
            {  
//因为我们都是默认从第一个做基准值,所以我们只需要与第一个换一下位置就好了,并且我们是在两端向中的,所以这样最规范最全面合适
                int tmp = arr[index];
                arr[index] = arr[left];
                arr[left] = tmp;
            }
            int pivot = partition3(arr, left, right);
            if(pivot - left >= 1) {
                stack.push(left);
                stack.push(pivot - 1);
            }
            if(right - pivot >= 1) {
                stack.push(pivot + 1);
                stack.push(right);
            }
            if(!stack.isEmpty()) {
                right = stack.pop();
                left = stack.pop();
            }else {
                break;
            }
        }while(true);
    }




6.5.2 队列模拟递归层序遍历

队列的先进先出,按照应有的顺序,一层一层的来。不像栈那种模拟深度优先(到底在归即为深度优先)

public static void quickSortNormal2(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        //队列模拟递归
        Queue<Integer> queue = new LinkedList<>();
        int left = 0;
        int right = arr.length - 1;
        do {
            int index = findMid(arr, left, right);
            {
//因为我们都是默认从第一个做基准值,所以我们只需要与第一个换一下位置就好了,并且我们是在两端向中的,所以这样最规范最全面合适
                int tmp = arr[index];
                arr[index] = arr[left];
                arr[left] = tmp;
            }
            int pivot = partition3(arr, left, right);
            if(pivot - left >= 1) {
                queue.offer(left);
                queue.offer(pivot - 1);
            }
            if(right - pivot >= 1) {
                queue.offer(pivot + 1);
                queue.offer(right);
            }
            if(!queue.isEmpty()) {
                left = queue.poll();
                right = queue.poll();
            }else {
                break;
            }
        }while(true);
    }



7. 归并排序


大家可以多看几次动图,这样理解起来会更好


分成很多小份排,然后逐渐变大份,(递归思想)


多用于多海量文件排序


7.1 递归实现

/**
     * 归并排序
     * 时间复杂度 O(N*logN)
     * 空间复杂度 O(N)
     * 【稳定的】
     * @param arr
     */
    public static void mergeSort(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        mergeSorter(arr, 0, arr.length - 1);
    }
    private static void mergeSorter(int[] arr, int left, int right) {
        if(left >= right) {
            return;
        }
        int mid = (left + right) >>> 1;
        mergeSorter(arr, left, mid);
        mergeSorter(arr, mid + 1, right);
        merge(arr, left, right, mid);
    }
//将序列划分为两部分,并且两部分是有序的,那么只需要合并有序序列就好
    private static void merge(int[] arr, int left, int right, int mid) {
        int left1 = left;
        int left2 = mid + 1;
        int len = right - left + 1;
        int[] tmp = new int[len];
        int num = 0;
        while(left1 <= mid && left2 <= right) {
            if(arr[left1] <= arr[left2]) { //决定稳定性
                tmp[num++] = arr[left1++];
            }else {
                tmp[num++] = arr[left2++];
            }
        }
        while(left1 <= mid) {
            tmp[num++] = arr[left1++];
        }
        while(left2 <= right) {
            tmp[num++] = arr[left2++];
        }
        System.arraycopy(tmp, 0, arr, left, len);
    }


7.2 非递归实现

重点就在于【gap】从小到大,之间按照原理来的

/**
     * 非递归归并排序
     * @param arr
     */
    public static void mergeSortNormal(int[] arr) {
        arr = Arrays.copyOf(arr, arr.length);
        //这不需要stack模拟递归,直接根据原理就好
        int gap = 1;
        while(gap < arr.length) {
            for (int left = 0; left < arr.length; left += gap * 2) {
                int right = gap * 2 + left - 1 < arr.length ? gap * 2 + left - 1 : arr.length - 1;
                int mid =  gap + left - 1 < arr.length ?  gap + left - 1 : arr.length - 1;
                merge(arr, left, right, mid);
            }
            gap *= 2;
        }
    }


7.3 归并排序链表(普通的排序可能会超时!)

7.3.1 选择排序链表

用选择排序的方式去排序链表,缺点就是代码复杂,有很多要考虑的

并且速度慢,力扣跑不过,时间复杂度达到N2

public ListNode sortList(ListNode head) {
        int count = 0;
        if(head == null) {
            return null;
        }
        ListNode ret = head;
        ListNode prevHead = null;
        while(head != null) {
            ListNode maxNode = head;
            ListNode cur = head;
            ListNode prev = head;
            while(cur != null) {
                if(cur.next != null && cur.next.val > maxNode.val) {
                    prev = cur;
                    maxNode = cur.next;
                }
                cur = cur.next;
            }
            if(count == 0) {
                prevHead = maxNode;
                count++;
            }if(maxNode == ret) {
                head = head.next;
                continue;
            }if(maxNode == head) {
                prev = prevHead;
                head = head.next;
            }
            ListNode linker = maxNode;
            prev.next = maxNode.next;
            linker.next = ret;
            ret = linker;
        }
        return ret;
    }




五万个数据,这种排序太慢了!

这里不做重点讲解,思路就是从后面选择一个最大的头插过去,重点也是要记住最大的最大的那个【尾结点】

7.3.2 递归排序链表

时间复杂度O(N * log2N), 空间复杂度O( 1 );


思路跟刚才归并怎么排一致,重点在于用快慢指针找到中点,节省速度


是可以先求长度然后一直用的(就是算一次长度,然后每次都用这个长度为基准,去找mid)

之后不断合并有序链表。


再看一次动图吧:

递归的重点就分清“整体感”,比如说下面的,我们就看做左右边已经弄好了,只要满足小问题(递归出口


),通过数学归纳法就能知道成立

ListNode left = sortList(head);
    ListNode right = sortList(tmp);
    public ListNode sortList(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }
        ListNode slow = head;
        ListNode fast = head.next;
        //避免当剩余两个节点时,中间节点变成右边那个,这样会死递归!
        //(打断链表更没有意义,右边链表是null,没用)
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode tmp = slow.next;
        slow.next = null; //打断链表


技巧1:平分链表(快慢指针在Java中应该是引用,或者下标)


快慢指针,慢指针应该走到中间偏前的一个位置【不然会死递归】

以两个节点为例子,快指针走两步,慢指针走一步,然后slow.next = null不就等于没有意义吗, 进入递归后,(左侧)依旧是两个节点,以此造成栈溢出!

解决方法:fast先走一步,最终slow停在中节点偏前

fast不先走一步,最终slow停在中节点偏后

ListNode left = sortList(head);
        ListNode right = sortList(tmp);
        ListNode ret = new ListNode(0);
        //临时头节点,最终不要即可,因为我们不能确定头结点是否是谁的
        ListNode cur = ret;
        while(left != null && right != null) {
            if(left.val <= right.val) {
                cur.next = left;
                left = left.next;
            }else {
                cur.next = right;
                right = right.next;
            }
            cur = cur.next;
        }
        cur.next = left != null ? left : right;
        return ret.next;
    }


技巧2: 给需要构造的链表提供一个起始节点,(就像珍珠需要有一个小石子,最终才能积累成珠)


ListNode ret = new ListNode(0);这一句代码,提供一个带头链表

目的是因为,我们不知道首节点是谁,毕竟尾入法在首节点需要判断

那我们不如直接给一个,最终不考虑进去就行了

技巧3:合并有序链表,不用多说


文章到此结束!谢谢观看 —>动图来源于网络

可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆!


这是我的代码仓库!(在马拉圈的22.12里)代码仓库 排序代码具体位置

目录
相关文章
|
9天前
|
存储 缓存 安全
Java 集合江湖:底层数据结构的大揭秘!
小米是一位热爱技术分享的程序员,本文详细解析了Java面试中常见的List、Set、Map的区别。不仅介绍了它们的基本特性和实现类,还深入探讨了各自的使用场景和面试技巧,帮助读者更好地理解和应对相关问题。
30 5
|
24天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
48 24
|
6天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
42 2
|
21天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
58 5
|
21天前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
46 5
|
23天前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
22天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
50 1
|
20天前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
181 9
|
1月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
32 1
下一篇
DataWorks