数据结构和算法

 

  • 冒泡排序

持续比较相邻元素,大的放到后面,所以大的会逐步往后放,所以称之为冒泡排序

package com.itstyle.seckill.common.algorithm;

/**
 * 冒泡排序
 */
public class BubbleSort {
    /**
     * 冒泡排序,持续比较相邻元素,大的挪到后面,因此大的会逐步往后挪,故称之为冒泡。
     * 复杂度分析:平均情况与最坏情况均为 O(n^2), 使用了 temp 作为临时交换变量,空间复杂度为 O(1).
     */
    public static void main(String[] args) {
        int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
        System.out.println("************冒泡排序************");
        System.out.println("排序前:");
        display(list);
        System.out.println("排序过程:");
        bubbleSort(list);
//        display(list);
    }

    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        if (list != null && list.length > 0) {
            for (int num : list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
    }

    /**
     * 冒泡排序算法
     */
    public static void bubbleSort(int[] list) {
        int len = list.length;
        // 做多少轮排序(最多length-1轮)
        for (int i = 0; i < len - 1; i++) {
            // 每一轮比较多少个
            for (int j = 0; j < len - 1 - i; j++) {
                if (list[j] > list[j + 1]) {
                    // 交换次序
                    int temp = list[j];
                    list[j] = list[j + 1];
                    list[j + 1] = temp;
                }
                System.out.print("第"+(i+1)+"轮比较过程:    ");
                display(list);
            }
            System.out.print("第"+(i+1)+"轮比较结果:");
            display(list);
        }
    }
}

解析:第一轮比较7次从第一位比较到最后一位  是  27与76  结果不换位置(第一位与第二位比较); 76与47比较 交换位置(第二位与第三位比较)76>47,47 76;接着是76与23比较(第三位与第四位)76>23交换位置  23 76;76与7比较(第四位与第五位)76>7 交换位置得到 7 76;76与32比较(第五位与第六位)76>32得到结果 32 76;76与19比较(第六位与第七位)76>19得到结果 19 76;76与86比较(第七位与第八位)76<86不换位置。

第二轮  比较6次,从第一位比较到第七位(倒数第二位),比较过程参考第一轮

第三轮 比较5次,从第一位比较到第六位(倒数第三位),比较过程同第一轮

依次直到结束

https://www.cnblogs.com/jingmoxukong/p/4329079.html

  • 直接插入排序

是一种最简单的排序方法,它的基本操作是将一个元素插入到已经排好的表中,从而得到一个新的、元素数增加1的有序表。即将插入的当前的元素的前面的元素都是有序的,要插入时,从当前这个元素的左边开始往前找(从后往前),比当前这个元素大的元素均往右移一个位置,最后把当前元素放在它应该放的位置保证是有序的。

 

package com.itstyle.seckill.common.algorithm;
/**
 * 直接插入排序
 */
public class InsertSort {
	/**
	 * 直接插入排序是一种最简单的排序方法,它的基本操作是将一个记录插入到已排好的有序的表中,从而得到一个新的、记录数增1的有序表。
         * 当前元素的前面元素均为有序,要插入时,从当前元素的左边开始往前找(从后往前找),比当前元素大的元素均往右移一个位置,最后把当前元素放在它应该呆的位置就行了。
     * 参考:https://www.cnblogs.com/mengdd/archive/2012/11/24/2786490.html
	 */
    public static void main(String[] args) {
    	int[] list = {27, 76, 47, 23, 7, 32, 19, 86};
        System.out.println("************直接插入排序************");
        System.out.println("排序前:");
        display(list);
//        System.out.println("排序后:");
        insertSort(list);
//        display(list);
    }

    /**
     * 直接插入排序算法
     */
    public static void insertSort(int[] list) {
    	int len = list.length ;
        // 从无序序列中取出第一个元素 (注意无序序列是从第二个元素开始的)
        for (int i = 1; i < len; i++) {
            int temp = list[i];
            int j;
            // 遍历有序序列
            // 如果有序序列中的元素比临时元素大,则将有序序列中比临时元素大的元素依次后移
            for (j = i - 1; j >= 0 && list[j] > temp; j--) {
                list[j + 1] = list[j];
            }
            // 将临时元素插入到腾出的位置中
            list[j + 1] = temp;
            System.out.println("排序过程从第"+(i+1)+"位与前"+i+"位比较结果如下:");
            display(list);
        }
    }

    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        if (list != null && list.length > 0) {
            for (int num :list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
    }
}

快速排序

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的数据都要小,然后再按此方法对这两部分进行快速排序,整个排序过程可以递归进行,达到排序的过程。

package com.itstyle.seckill.common.algorithm;
/**
 * 快速排序
 */
public class QuickSort {
	/**
	 * 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
	 */
    public static void main(String[] args) {
        int[] list = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
        System.out.println("************快速排序************");
        System.out.println("排序前:");
        display(list);
        System.out.println("排序后:");
        quickSort(list, 0, list.length - 1);
        display(list);
    }

    /**
     * 快速排序算法
     */
    public static void quickSort(int[] list, int left, int right) {
        if (left < right) {
            // 分割数组,找到分割点
            int point = partition(list, left, right);

            // 递归调用,对左子数组进行快速排序
            quickSort(list, left, point - 1);
            // 递归调用,对右子数组进行快速排序
            quickSort(list, point + 1, right);
        }
    }

    /**
     * 分割数组,找到分割点
     */
    public static int partition(int[] list, int left, int right) {
        // 用数组的第一个元素作为基准数
        int first = list[left];
        while (left < right) {
            System.out.println("left:"+left+":"+"right:"+right+"   "+list[right]+">="+first);
            while (left < right && list[right] >= first) {
                right--;
                System.out.println("右分割点right:"+right+"左分割点left:"+left+" "+list[right]+">="+first);
            }
            System.out.println("右分割点right:"+right+"左分割点left:"+left+"  list[right]:"+list[right]+"  list[left]"+list[left]);
            // 交换
            swap(list, left, right);
            System.out.println();

            System.out.println("left: "+left+":"+"right: "+right+"   "+list[left]+"<="+first);
            while (left < right && list[left] <= first) {
                left++;
                System.out.println("右分割点right:"+right+"左分割点left:"+left+" "+list[left]+"<="+first);
            }
            System.out.println("右分割点right:"+right+"左分割点left:"+left+"  list[right]:"+list[right]+"  list[left]"+list[left]);
            // 交换
            swap(list, left, right);
            System.out.println();
        }
        // 返回分割点所在的位置
        return left;
    }

    /**
     * 交换数组中两个位置的元素
     */
    public static void swap(int[] list, int left, int right) {
        int temp;
        if (list != null && list.length > 0) {
            temp = list[left];
            list[left] = list[right];
            list[right] = temp;
            System.out.println("将list[left]与list[right]交换位置后的排序结果:");
            display(list);
        }
    }

    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        if (list != null && list.length > 0) {
            for (int num :list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
    }
}

归并排序:

package com.itstyle.seckill.common.algorithm;
/**
 * 归并排序
 */
public class MergeSort {
	/**
	 * 归并排序(Merge Sort)与快速排序思想类似:将待排序数据分成两部分,继续将两个子部分进行递归的归并排序;然后将已经有序的两个子部分进行合并,最终完成排序。
	 * 其时间复杂度与快速排序均为O(nlogn),但是归并排序除了递归调用间接使用了辅助空间栈,还需要额外的O(n)空间进行临时存储。从此角度归并排序略逊于快速排序,但是归并排序是一种稳定的排序算法,快速排序则不然。
     * 所谓稳定排序,表示对于具有相同值的多个元素,其间的先后顺序保持不变。对于基本数据类型而言,一个排序算法是否稳定,影响很小,但是对于结构体数组,稳定排序就十分重要。例如对于student结构体按照关键字score进行非降序排序:
	 */
    public static void main(String[] args) {
        int[] list = {50, 10, 90, 30, 70};
        System.out.println("************归并排序************");
        System.out.println("排序前:");
        display(list);
        System.out.println("排序后:rear "+(list.length - 1));
        mergeSort(list, new int[list.length], 0, list.length - 1);
//        display(list);
    }

    /**
     * 归并排序算法
     * @param list     待排序的列表
     * @param tempList 临时列表
     * @param head     列表开始位置
     * @param rear     列表结束位置
     */
    public static void mergeSort(int[] list, int[] tempList, int head, int rear) {
        if (head < rear) {
            System.out.println("head --"+head+"-- rear "+rear);
            // 取分割位置
            int middle = (head + rear) / 2;
            System.out.println("head --"+head+" middle "+middle);
            // 递归划分列表的左序列
            mergeSort(list, tempList, head, middle);
            System.out.println("middle 右"+(middle+1)+" rear "+rear);
            // 递归划分列表的右序列
            mergeSort(list, tempList, middle + 1, rear);
            // 列表的合并操作
            System.out.println("  head: 列表合并"+head+"  middle: "+(middle+1)+"  rear: "+rear);
            merge(list, tempList, head, middle + 1, rear);
            System.out.println();
        }
    }

    /**
     * 合并操作(列表的两两合并)
     * @param list
     * @param tempList
     * @param head
     * @param middle
     * @param rear
     */
    public static void merge(int[] list, int[] tempList, int head, int middle, int rear) {
        //head为头 左指针尾
        int headEnd = middle - 1;
        // 右指针头,rear为尾
        int rearStart = middle;
        // 临时列表的下标
        int tempIndex = head;
        // 列表合并后的长度
        int tempLength = rear - head + 1;

        System.out.println("list   ---  ");
        display(list);
        System.out.println("tempList-- --  ");
        display(tempList);

        // 先循环两个区间段都没有结束的情况
        while ((headEnd >= head) && (rearStart <= rear)) {
            // 如果发现右序列大,则将此数放入临时列表
            if (list[head] < list[rearStart]) {
                System.out.println("if list[head] "+list[head]+" list[rearStart] "+list[rearStart]);
                System.out.println("tempIndex "+tempIndex+" head "+head);
                tempList[tempIndex++] = list[head++];
                System.out.println("tempIndex "+tempIndex+" head "+head);

            } else {
                System.out.println("else list[head] "+list[head]+" list[rearStart] "+list[rearStart]);
                System.out.println("tempIndex "+tempIndex+" rearStart "+rearStart);
                tempList[tempIndex++] = list[rearStart++];
                System.out.println("tempIndex "+tempIndex+" rearStart "+rearStart);
            }
        }

        System.out.println("list   ---  ");
        display(list);
        System.out.println("tempList-- --  ");
        display(tempList);

        // 判断左序列是否结束
        while (head <= headEnd) {
            System.out.println("左序列是否结束head <= headEnd  head: "+head+" headEnd: "+headEnd);
            System.out.println("左序列是否结束head <= headEnd tempIndex "+tempIndex+" head "+head);
            tempList[tempIndex++] = list[head++];
        }

        // 判断右序列是否结束
        while (rearStart <= rear) {
            System.out.println("右序列是否结束rearStart <= rear  rearStart: "+rearStart+" rear: "+rear);
            tempList[tempIndex++] = list[rearStart++];
            System.out.println("右序列是否结束 tempIndex "+tempIndex+" head "+head);
        }
        System.out.println("list   ---  ");
        display(list);
        System.out.println("tempList-- --  ");
        display(tempList);
        // 交换数据
        for (int i = 0; i < tempLength; i++) {
            System.out.println("list[rear] "+list[rear]+"  tempList[rear] "+tempList[rear]);
            list[rear] = tempList[rear];
            System.out.println("交换数据:执行 list[rear] = tempList[rear] 此时rear的值为:"+rear+"   交换之后的list如下:");
            rear--;
            display(list);
            System.out.println();
            System.out.println();
        }
        System.out.println("交换结果:");
        display(list);
        System.out.println("此时的rear: "+rear);
    }

    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        if (list != null && list.length > 0) {
            for (int num :list) {
                System.out.print(num + " ");
            }
            System.out.println("");
        }
    }
}

注意观察下图中控制台输出的部分middle=2时 rear=4;middle=1,rear=2;middle=0,rear=1

当不满足条件时:

下一步

不满足条件时

下一步  记得下图debug的那一部分  中middle的值为0 rear的值为 1

走完得结果为

接下来走的时下图中debug的部分此时 middle的值为1,rear=2

这部分执行完得到的结果为

下一步执行到如下图,此时 middle为2,rear为4

下一步

即得到最终结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值