算法学习之排序、LRU算法

文章目录

排序

1)冒泡排序

public void bubbleSort(int[] arr){
	for (int i = 0; i < arr.length; i++) {
        //外层循环,遍历次数
        for (int j = 0; j < arr.length - i - 1; j++) {
            //内层循环,升序(如果前一个值比后一个值大,则交换)
            //内层循环一次,获取一个最大值
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j + 1];
                arr[j + 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}
  • 将序列中所有元素两两比较,将最大的放在最后面。
  • 将剩余序列中所有元素两两比较,将最大的放在最后面。
  • 重复第二步,直到只剩下一个数。

2)选择排序

public void selectionSort(int[] arr){
	 //选择
    for (int i = 0; i < arr.length; i++) {
        //默认第一个是最小的。
        int min = arr[i];
        //记录最小的下标
        int index = i;
        //通过与后面的数据进行比较得出,最小值和下标
        for (int j = i + 1; j < arr.length; j++) {
            if (min > arr[j]) {
                min = arr[j];
                index = j;
            }
        }
        //然后将最小值与本次循环的,开始值交换
        int temp = arr[i];
        arr[i] = min;
        arr[index] = temp;
    }
}
  • 遍历整个序列,将最小的数放在最前面。
  • 遍历剩下的序列,将最小的数放在最前面。
  • 重复第二步,直到只剩下一个数。

说明:如果每次比较都交换,那么就是交换排序;如果每次比较完一个循环再交换,就是简单选择排序。

3)插入排序

public static void insertSort(int [] a){
    int len=a.length;
    int insertNum;		//要插入的数
    for(int i=1;i<len;i++){		//因为第一次不用,所以从1开始
        insertNum=a[i];
        int j=i-1;		//序列元素个数
        while(j>=0&&a[j]>insertNum){		//从后往前循环,将大于insertNum的数向后移动
            a[j+1]=a[j];		//元素向后移动
            j--;
        }
        a[j+1]=insertNum;		//找到位置,插入当前元素
    }
}
  • 首先设定插入次数,即循环次数,for(int i=1;i<length;i++),1个数的那次不用插入。
  • 设定插入数和得到已经排好序列的最后一个数的位数。insertNum和j=i-1。
  • 从最后一个数开始向前循环,如果插入数小于当前数,就将当前数向后移动一位。
  • 将当前数放置到空着的位置,即j+1。

4)希尔排序

public void sheelSort(int [] a){
    //希尔排序(插入排序变种版)
    for (int i = arr.length / 2; i > 0; i /= 2) {
        //i层循环控制步长
        for (int j = i; j < arr.length; j++) {
            //j控制无序端的起始位置
            for (int k = j; k > 0  && k - i >= 0; k -= i) {
                if (arr[k] < arr[k - i]) {
                    int temp = arr[k - i];
                    arr[k - i] = arr[k];
                    arr[k] = temp;
                } else {
                    break;
                }
            }
        }
        //j,k为插入排序,不过步长为i
    }
}
  • 基本上和插入排序一样的道理
  • 不一样的地方在于,每次循环的步长,通过减半的方式来实现
  • 说明:基本原理和插入排序类似,不一样的地方在于。通过间隔多个数据来进行插入排序。

5)归并排序

import org.junit.Test;
public class MergeSort {
    //两路归并算法,两个排好序的子序列合并为一个子序列
    public void merge(int []a,int left,int mid,int right){
        int []tmp=new int[a.length];//辅助数组
        int p1=left,p2=mid+1,k=left;//p1、p2是检测指针,k是存放指针

        while(p1<=mid && p2<=right){
            if(a[p1]<=a[p2])
                tmp[k++]=a[p1++];
            else
                tmp[k++]=a[p2++];
        }

		//如果第一个序列未检测完,直接将后面所有元素加到合并的序列中
        while(p1<=mid) tmp[k++]=a[p1++];
        while(p2<=right) tmp[k++]=a[p2++];//同上

        //复制回原素组
        for (int i = left; i <=right; i++) 
            a[i]=tmp[i];
    }

    public void mergeSort(int [] a,int start,int end){
        if(start<end){//当子序列中只有一个元素时结束递归
            int mid=(start+end)/2;//划分子序列
            mergeSort(a, start, mid);//对左侧子序列进行递归排序
            mergeSort(a, mid+1, end);//对右侧子序列进行递归排序
            merge(a, start, mid, end);//合并
        }
    }

    @Test
    public void test(){
        int[] a = { 49, 38, 65, 97, 76, 13, 27, 50 };
        mergeSort(a, 0, a.length-1);
        System.out.println("排好序的数组:");
        for (int e : a)
            System.out.print(e+" ");
    }
}
  • 选择相邻两个数组成一个有序序列。
  • 选择相邻的两个有序序列组成一个有序序列。
  • 重复第二步,直到全部组成一个有序序列。

6)快速排序
参考

public class QuickSort {
    public static void quickSort(int[] arr,int low,int high){
        int i,j,temp,t;
        if(low>high){
            return;
        }
        i=low;
        j=high;
        //temp就是基准位
        temp = arr[low];
 
        while (i<j) {
            //先看右边,依次往左递减
            while (temp<=arr[j]&&i<j) {
                j--;
            }
            //再看左边,依次往右递增
            while (temp>=arr[i]&&i<j) {
                i++;
            }
            //如果满足条件则交换
            if (i<j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }
 
        }
        //最后将基准为与i和j相等位置的数字交换
         arr[low] = arr[i];
         arr[i] = temp;
        //递归调用左半数组
        quickSort(arr, low, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, high);
    }
 
 
    public static void main(String[] args){
        int[] arr = {10,7,2,4,7,62,3,4,2,1,8,9,19};
        quickSort(arr, 0, arr.length-1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

7)基数排序
参考

LRU

LRU 缓存淘汰算法就是一种常用策略。LRU 的全称是 Least Recently Used,也就是说我们认为最近使用过的数据应该是是「有用的」,很久都没用过的数据应该是无用的,内存满了就优先删那些很久没用过的数据。

146. LRU缓存机制

题解:

  1. 继承LinkedHashMap实现
  2. 要满足get()put()都在O(1)的时间内完成,就必须要满足以下条件:
  • 首先, cache 中的元素必须有时序,以区分最近使用的和久未使用的数据,当容量满了之后要删除最久未使用的那个元素腾位置。
  • 其次,我们要在 cache 中快速找某个 key 是否已存在并得到对应的 val
  • 每次访问 cache 中的某个 key,需要将这个元素变为最近使用的,也就是说 cache 要支持在任意位置快速插入和删除元素。哈希链表 LinkedHashMap就可以满足以上条件
class LRUCache {
    int cap;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();
    public LRUCache(int capacity) { 
        this.cap = capacity;
    }

    public int get(int key) {
        if (!cache.containsKey(key)) {
            return -1;
        }
        // 将 key 变为最近使用
        makeRecently(key);
        return cache.get(key);
    }

    public void put(int key, int val) {
        if (cache.containsKey(key)) {
            // 修改 key 的值
            cache.put(key, val);
            // 将 key 变为最近使用
            makeRecently(key);
            return;
        }

        if (cache.size() >= this.cap) {
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }
        // 将新的 key 添加链表尾部
        cache.put(key, val);
    }

    private void makeRecently(int key) {
        int val = cache.get(key);
        // 删除 key,重新插入到队尾
        cache.remove(key);
        cache.put(key, val);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值