算法学习(1)冒泡 插入归并 链表翻转

 算法学习笔记

 

冒泡排序  时间复杂度O(n2)

public class BubbleSort {
    public static void main(String[] args) {
        int[] array={7,8,9,4,5,6,2,1,3};
        sort(array);
        for (int i = 0; i <array.length ; i++) {
            System.out.print(array[i]+",");
        }

    }
    public static void sort(int[] array){
        for (int i = 0; i <array.length-1 ; i++) {
            for (int j = 0; j <array.length-1-i ; j++) {
                if (array[j]>array[j+1]){
                    int temp=array[j+1];
                    array[j+1]=array[j];
                    array[j]=temp;
                }//if
            } // forj
        } //fori
    }  //sort

 //改进  原理记录最后一位冒泡交换的下标,
    public static void sort2(int[] array){
        int m=array.length;
            while (m > 1) {
                int lastExchangeIndex = 1;
                for (int j = 0; j < array.length-1; j++) {
                    if (array[j] > array[j + 1]) {
                        swap(array, j, j + 1);
                        lastExchangeIndex = j;
                    }else {
                        m = lastExchangeIndex;  //只要最后一位交换的下标不是0,就一直循环
                    }
                } // forj
            } //while

        }  //sort

}

插入排序  时间复杂度 O(n2)

public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {1,4,5,8,6,7,8,21,33};
        insertSort(arr);
        for (int ele:arr) {
            System.out.println(ele);
        }
    }
    //插入排序
    public  static void insertSort(int[] arr){
        for (int j=1;j<arr.length;j++){
            int key =arr[j];
            int i=j-1;
            while(i>-1&&arr[i]>key){
                arr[i+1]=arr[i];
                i=i-1;
            }
            arr[i+1]=key;
        }
    }
}

选择排序

public static void  select_sort(int[] arr){
        int n=arr.length;
        for(int i=0;i<n;i++){
        int minPosition=sacnForMin(arr,i,n-1);
        swap(arr,arr[i],arr[minPosition]);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int temp=arr[j];
        arr[j]=arr[i];
        arr[i]=temp;
    }
    private static int sacnForMin(int[] arr, int i, int i1) {
        int min=arr[i];
        int position=i;
        for (int j = i; j < i1; j++) {
            if (arr[j]<min){
                min=arr[j];
                position=j;
            }
        }
        return position;
    }

归并排序 : 归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。每次合并操作的平均时间复杂度为O(n),而完全二叉树的深度为|log2n|。总的平均时间复杂度为O(nlogn)。而且,归并排序的最好,最坏,平均时间复杂度均为O(nlogn)。


import java.util.Arrays;
public class MergeSort {
    public static void main(String []args){
        int []arr = {9,8,7,6,5,4,3,2,1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static void sort(int []arr){
        int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
         mergeSort(arr,0,arr.length-1,temp);
    }
    private static void  mergeSort(int[] arr,int left,int right,int []temp){
        if(left<right){
            int mid = (left+right)/2;
            mergeSort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
            mergeSort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
            merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
        }
    }
    private static void merge(int[] arr,int left,int mid,int right,int[] temp){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        while (i<=mid && j<=right){
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }
}

归并排序问题延伸

利用归并排序求一个数组中的逆序对

public class MergeSort {
    private static int ORDER_COUNT=0;
    public static void main(String []args) throws InterruptedException {
        int []arr = {9,8,7,6,5,4,3,2,1};
        sort(arr);
        System.out.println(Arrays.toString(arr));
        System.out.println(ORDER_COUNT);
        int [] arr2={2,1,5,3,2};
        Thread.sleep(1000);

        ORDER_COUNT=0;
        sort(arr2);
        System.out.println(Arrays.toString(arr2));
        System.out.println(ORDER_COUNT);
    }
    public static void sort(int []arr){
        int []temp = new int[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
        mergeSort(arr,0,arr.length-1,temp);
    }
    private static void  mergeSort(int[] arr,int left,int right,int []temp){
        if(left<right){
            int mid = (left+right)/2;
            mergeSort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
            mergeSort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
            merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
        }
    }
    private static void merge(int[] arr,int left,int mid,int right,int[] temp){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        //求解归逆序对中的数量只需要改进一下while循环方法
        while (i<=mid && j<=right){
            if(arr[i]<=arr[j]){  //此时没有逆序对
                temp[t++] = arr[i++];
            }else {  //否则产生了逆序对,我们需要对逆序对做出统计
                temp[t++] = arr[j++];
                ORDER_COUNT+=mid-i+1;//+1的作用是将0的序列变为按下标的序列,
                // mid+1是左边的总数,i是第一个比右边数值大的坐标
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }
}

 

快速排序 

//快速排序
  // 分而治之  先选一个枢纽  左边元素全部小于枢纽  右边元素全部大于枢纽
//1.第一步选取主元   取头中尾的中位数  例如8,12,3的中位数就是8
  //选取主元
    public static void Median(int[] arr, int left, int right) {
        int center = (left + right) / 2;  // 一定是左中右的顺序  left<center<right
        if (arr[left] > arr[center]) swap(arr, left, center);

        if (arr[left] > arr[right]) swap(arr, left, right);

        if (arr[center] > arr[right]) swap(arr, center, right);

        swap(arr, right-1, center);   //之后只需考虑arr[left+1]....arr[right-2]


    }

    //子集划分
    public static void quickSoort(int[] arr, int left, int right) {
        if (left < right) {
            Median(arr, left, right);
            int pivot = right - 1;
            int i = left;  //左指针
            int j = right - 1;  //右指针
            while (true){
                while (arr[++i] < arr[pivot]) { }   //i=left+1
                while (j > left && arr[--j] > arr[pivot]) { }    // right-2
                if (i < j) {
                    swap(arr, i, j);
                } else {
                    break;
                }
            }
            if (i < right) {
                swap(arr, i, right - 1);
            }
            quickSoort(arr, left, i - 1);
            quickSoort(arr, i + 1, right);
    }//if

    }


    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

表排序v :待排元素不是一个简单的整数,待排元素是一个类,一个对象,你在排序的过程中不需要移动原始数据

 物理排序: n个数字的排列由若干个独立的环组成


桶排序:

基数排序 : 次位优先

多关键字排序:

vivo的面试题 

import java.util.Arrays;
/**
 * 比较两个字符串大小规则如下:
 * 1.如果两个字符串长度不相同,则短字符串比长字符串小
 * 2.如果两个字符串长度相同,则按照A~ Z,a~z,0~9的大小关系排序
 */
public class StringSort {
    public static void main(String[] args) {
        String[] strs = {"a", "Abc", "123", "1", "abc", "CBD", "abcd", "a"};
        sort(strs);
        for (String str:strs) {
            System.out.print(str+"\t");
        }
    }
    /**
     * 比较a和b的大小
     * @param a
     * @param b
     * @return
     */



 public static boolean less2(String a, String b){
        if (a.length()<b.length()) return true;
        else if (a.length()==b.length()){
            for (int i = 0; i <a.length() ; i++) {
                if (a.charAt(i)>='0'&&a.charAt(i)<='9') {
                    if (b.charAt(i) >= '0' && b.charAt(i) <= '9') 
                     return b.charAt(i)>a.charAt(i)?true:false;
                    if (b.charAt(i)>='A'&&b.charAt(i)<='z') return false;
                }else {
                    if (b.charAt(i) >= '0' && b.charAt(i) <= '9') return true;
                    else return b.charAt(i)>a.charAt(i)?true:false;
                }
            }
        }
        return false;
    }





    public static boolean less(String a,String b){
        if (a.length()<b.length()) {
            return true;
        }else if (a.length()>b.length()) {
            return false;
        }else{
            for (int i = 0;i<a.length();i++){
                if(a.charAt(i)>=48&&a.charAt(i)<=57){
                    if(b.charAt(i)>=48&&b.charAt(i)<=57){
                        return a.charAt(i)<b.charAt(i);
                    }else{
                        return false;
                    }
                }else{
                    if(b.charAt(i)>=48&&b.charAt(i)<=57){
                        return true;
                    }else{
                        return (int)a.charAt(i)<(int)b.charAt(i);
                    }
                }
            }
            return true;
        }
    }
    /**
     * 以下为归并排序模板
     * @param arr
     */
    public static void sort(String []arr){
        String []temp = new String[arr.length];//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
        mergeSort(arr,0,arr.length-1,temp);
    }
    private static void  mergeSort(String[] arr,int left,int right,String []temp){
        if(left<right){
            int mid = (left+right)/2;
            mergeSort(arr,left,mid,temp);//左边归并排序,使得左子序列有序
            mergeSort(arr,mid+1,right,temp);//右边归并排序,使得右子序列有序
            merge(arr,left,mid,right,temp);//将两个有序子数组合并操作
        }
    }
    private static void merge(String[] arr,int left,int mid,int right,String[] temp){
        int i = left;//左序列指针
        int j = mid+1;//右序列指针
        int t = 0;//临时数组指针
        while (i<=mid && j<=right){
            if(less(arr[i],arr[j])){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//将左边剩余元素填充进temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//将右序列剩余元素填充进temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //将temp中的元素全部拷贝到原数组中
        while(left <= right){
            arr[left++] = temp[t++];
        }
    }
}

 

 

 

牛课练习  反转数组

题目描述

public class ListNode {
    int val;
    ListNode next = null;
    public ListNode() {
    }
    ListNode(int val) {
        this.val = val;
    }
}

 

输入一个链表,反转链表后,输出新链表的表头。

//反转数组
 public ListNode ReverseList(ListNode head){
     if(head==null){
        return null;
 }
     ListNode next=null;
     listNode pre=null;
      while(head!=null){
        next=head.next;
        head.next=pre;
        pre=head;
        head=next;
    }
        retuen pre;
}

衍生  局部链表反转 

 

public class ReverseList {

    public static void main(String[] args) {
        ListNode l1=new ListNode(1);
        ListNode l2=new ListNode(2);
        ListNode l3=new ListNode(3);
        ListNode l4=new ListNode(4);
        ListNode l5=new ListNode(5);
        ListNode l6=new ListNode(6);
        ListNode l7=new ListNode(7);
        ListNode l8=new ListNode(8);
        l1.next=l2;
        l2.next=l3;
        l3.next=l4;
        l4.next=l5;
        l5.next=l6;
        l6.next=l7;
        l7.next=l8;
        ListNode next=l1;
        for (int i = 0; i <8 ; i++) {
            System.out.print(next.val);
            next=next.next;
        }
        System.out.println();

//        ListNode newHead=reverseList(l1);
//        for (int i = 0; i <8 ; i++) {
//            System.out.println(newHead.val);
//            newHead=newHead.next;
//        }

        reversePartOfList(l1,l1,l8);
        ListNode frist=l8;
        for (int i = 0; i <8 ; i++) {
            System.out.print(frist.val);
            frist=frist.next;
        }
    }

    //下面开始测试局部链表翻转  123456789----123 987654    123456789     123 654 789
     public static void reversePartOfList(ListNode node,ListNode begin,ListNode end){

         ListNode p1=new ListNode(0);
         p1.next=node;
         ListNode p2=new ListNode(9);
         ListNode temp0=p1;
         while(temp0.next!=null){
             temp0=temp0.next;
         } temp0.next=p2;   //将9 和 尾部最后一个节点相连



         ListNode temp1=p1;
        while (temp1.next!=begin){
             temp1=temp1.next;
        } p1=temp1;//哨兵1  记录断开的前一个节点
         System.out.println(p1.val);


         ListNode temp2=p1;
         while (temp2.next!=null&&temp2.next!=end){
             temp2=temp2.next;
         }
         p2=temp2.next.next;//哨兵  记录断开的后一个节点
         System.out.println(p2.val);

         end.next=null;
         p1.next=null;
         ListNode partBegin=reverseList(begin);

         ListNode temp3=partBegin;
         while (temp3.next!=null){
             temp3=temp3.next;
         }
         ListNode partEnd=temp3;
         System.out.println(partBegin.val+"   "+partEnd.val);
         p1.next=partBegin;
         partEnd.next=p2;


     }

    //题目描述
    //输入一个链表,反转链表后,局部翻转链表
    public static ListNode reverseList(ListNode head) {
        if (head==null){
            return null;
        }
        ListNode pre=null;
        ListNode next=null;
        while(head!=null){
            next=head.next;
            head.next=pre;
            pre=head;
            head=next;
        }
            return pre;
    }
}

 代码较为冗余   经过多个测试代码 是正确的   如果有问题 还望指出。

 

 头插法局部链表反转

逻辑  四个指针 head  pre  cur next     head为哨兵不动  pre为尾节点值不变位置在移动   每次就是将cur插在head后面,将pre与next相连,举例  1 2 3 4        翻转23      就是 1=head   2=pre   3=cur  4=next  将3插在2前 完成头插

                                             翻转234    就是在上一步基础上      将4插在 32前面 1后面   就完成了翻转

核心代码

//找到   head pre cur 三个节点   构造next节点
next=cur.next;
pre.next=head.next;
head.next=cur;
pre.next=next;
cur=next;

0 1 2 3 4 5 6 7 8 
第i次0    next值3   cur值2   head值0   pre值1    
第i次1    next值4   cur值3   head值0   pre值1   
第i次2    next值5   cur值4   head值0   pre值1   
第i次3    next值6   cur值5   head值0   pre值1   
第i次4    next值7   cur值6   head值0   pre值1   
第i次5    next值8   cur值7   head值0   pre值1   
0 7 6 5 4 3 2 1 8 

public class ReverseListByHead {
    public static void main(String[] args) {
        ListNode head=new ListNode();
        ListNode l1=new ListNode(1);
        ListNode l2=new ListNode(2);
        ListNode l3=new ListNode(3);
        ListNode l4=new ListNode(4);
        ListNode l5=new ListNode(5);
        ListNode l6=new ListNode(6);
        ListNode l7=new ListNode(7);
        ListNode l8=new ListNode(8);
        head.next=l1;
        l1.next=l2;
        l2.next=l3;
        l3.next=l4;
        l4.next=l5;
        l5.next=l6;
        l6.next=l7;
        l7.next=l8;
        print(head);
        reverseByHead(head,1,7);
        print(head);
    }



    public static void print(ListNode head) {
        while (head != null) {
            System.out.print(head.val + " ");
            head = head.next;
        }
        System.out.println();
    }
    /**
     * 翻转链表的从结点m到结点n的部分
     *
     * @param head 头节点
     * @param from 翻转的开始位置
     * @param to 翻转的结束位置
     * @return 翻转后的新链表
    12345678        1 234567 8    1 765432 8
    初始化的Head  头节点为空
     */
    public static void reverseByHead(ListNode head, int from, int to) {
        if(from>to)return;
        ListNode cur=head.next;
        int i;
        for ( i = 0; i <from-1 ; i++) {  //找到断开的前一个节点
            head=cur;    //将前一个节点 标记为 head
            cur=cur.next;    //
        }
        ListNode pre=cur;   //反转的第一个节点即使翻转后的最后一个节点
        cur=cur.next;
        to--;              //必须减减  否则会数组越界
        ListNode next=null;
        for (;i<to;i++){
            next=cur.next;
            cur.next=head.next; //  1234 5678    1=head    2= pre    3=cur    4=next       3.next=(1.next)2    3->2
            head.next=cur;       // 1->3->2
            pre.next=next;        //1->3->2->4 5678
            System.out.println("第i次"+i+ "    "+"next值"+next.val+"   "+"cur值"+cur.val+"   "+"head值"+head.val+"   "+"pre值"+pre.val+"   ");
            cur=next;           //推火车   13245678        1=head   3=head.next  2=pre   4=cur   5=next
        }

    }
}

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值