05.位图和比较器的简单应用
目录
- 位图和比较器的简单应用
- 一、位图
- 1.位图的功能
- 2.位图的好处
- 3.位图的实现
- 二、用位运算实现加减乘除
- 1.加法
- 2.减法
- 3.乘法
- 4.除法
- 三、位运算完成大小比较
- 四、比较器
- 1.应用在系统排序方法中
- 2.应用在与排序有关的结构中优先级队列(堆)、有序表
- 五、合并多个有序链表
- 六、写在后面
位图和比较器的简单应用
一、位图
1.位图的功能
记录信息
例如,用一个 int
类型的变量的每个二进制位来记录 0−310-310−31 的出现情况。
2.位图的好处
可以用更小的空间来实现 map 的功能。
3.位图的实现
import java.util.HashSet;public class Code02_BitMap2 {// 位图的实现public static class BitMap {private long[] bits;public BitMap(int max) {bits = new long[(max + 64) >> 6];}public void add(int num) {// 注意要用 1Lbits[num >> 6] |= (1L << (num & 63));}public void delete(int num) {bits[num >> 6] &= ~(1L << (num & 63));}public boolean contains(int num) {return (bits[num >> 6] & (1L << (num & 63))) != 0;}}//对数器public static void main(String[] args) {System.out.println("测试开始!");int max = 10000;BitMap bitMap = new BitMap(max);HashSet<Integer> set = new HashSet<>();int testTime = 10000000;for (int i = 0; i < testTime; i++) {int num = (int) (Math.random() * (max + 1));double decide = Math.random();if (decide < 0.333) {bitMap.add(num);set.add(num);} else if (decide < 0.666) {bitMap.delete(num);set.remove(num);} else {if (bitMap.contains(num) != set.contains(num)) {System.out.println("Oops!");break;}}}for (int num = 0; num <= max; num++) {if (bitMap.contains(num) != set.contains(num)) {System.out.println("Oops!");}}System.out.println("测试结束!");}}
二、用位运算实现加减乘除
用位运算实现+ - * /
1.加法
// 测试链接:https://leetcode.cn/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
public class BitAddMinusMultiDiv {public static int add(int a, int b) {int sum = a;while (b != 0) {sum = a ^ b; // 不进位和b = (a & b) << 1; // 进位和a = sum;}return sum;}}
2.减法
// 测试链接: 无
public class BitAddMinusMultiDiv {// a - b => a + (-b) public static int minus(int a, int b) {return add(a, negNum(b));}// n => -npublic static int negNum(int n) {return add(~n, 1);}public static int add(int a, int b) {int sum = a;while (b != 0) {sum = a ^ b;b = (a & b) << 1;a = sum;}return sum;}}
3.乘法
原理同十进制乘法
// 测试链接:https://leetcode.cn/problems/recursive-mulitply-lcci/
public class BitAddMinusMultiDiv {// 递归方法 支持负数public int multiply(int A, int B) {if (B == 0) return 0;if (B == 1) return A;return multiply(A, (B & 1)) + multiply(A << 1, B >>> 1);}// 非递归方法 支持负数// a * b => a 逐位乘 b 的二进制 ,并且错位相加public static int multi(int a, int b) {int res = 0;while (b != 0) {if ((b & 1) != 0) {res = add(res, a); // 加错位后的结果}a <<= 1; // a 左移一位 即错位b >>>= 1; // b 无符号右移一位,即消除最右边用过的一位数}return res;}public static int add(int a, int b) {int sum = a;while (b != 0) {sum = a ^ b;b = (a & b) << 1;a = sum;}return sum;}}
4.除法
// 测试链接:https://leetcode.cn/problems/divide-two-integers/
public class BitAddMinusMultiDiv {public static int add(int a, int b) {int sum = a;while (b != 0) {sum = a ^ b;b = (a & b) << 1;a = sum;}return sum;}public static int negNum(int n) {return add(~n, 1);}public static int minus(int a, int b) {return add(a, negNum(b));}public static int multi(int a, int b) {int res = 0;while (b != 0) {if ((b & 1) != 0) {res = add(res, a);}a <<= 1;b >>>= 1;}return res;}public static boolean isNeg(int n) {return n < 0;}public static int div(int a, int b) {int x = isNeg(a) ? negNum(a) : a;int y = isNeg(b) ? negNum(b) : b;int res = 0;for (int i = 30; i >= 0; i = minus(i, 1)) {if ((x >> i) >= y) {res |= (1 << i);x = minus(x, y << i);}}return isNeg(a) ^ isNeg(b) ? negNum(res) : res;}public static int divide(int a, int b) {if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {return 1;} else if (b == Integer.MIN_VALUE) {return 0;} else if (a == Integer.MIN_VALUE) {if (b == negNum(1)) {return Integer.MAX_VALUE;} else {// a / b// (a + 1) / b == c// a - (b * c) = d// d / b = e// c + eint c = div(add(a, 1), b);return add(c, div(minus(a, multi(c, b)), b));}} else {return div(a, b);}}}
三、位运算完成大小比较
如何不用任何比较判断语句,就可以返回两个数中较大的那个
/*** @author 杨思远* @version 1.0* @title 位运算完成大小比较* @date 2022/7/16 0:52* @description 本方法原创 不一定为最优解 a < b => -1 a == b => -1 a > b => 1*/
public class BitComparisonOfSize {// 只使用 !=public static int compare(int a, int b) {if (a >>> 31 != b >>> 31) return b >>> 31 - a >>> 31;for (int i = 30; i > 0; i--) {if (a >>> i != b >>> i) return a >>> i - b >>> i;}return 0;}// 不使用任何比较判断语句 ( > < = != >= <= )public static int compare2(int a, int b) {return a - b >>> 31;}public static void main(String[] args) {System.out.println("测试开始");for (int i = 0; i < 1000000; i++) {int a = (int) (Math.random() * Integer.MIN_VALUE) * Math.random() < 0.5 ? 1 : -1;int b = (int) (Math.random() * Integer.MIN_VALUE) * Math.random() < 0.5 ? 1 : -1;int res = compare(a, b);int res2 = compare2(a, b);int acceptedAnswer = Integer.compare(a, b);if (res != acceptedAnswer || res2 != acceptedAnswer) {System.out.println("错误:a:" + a + ",b:" + b);}}System.out.println("测试结束");}}
四、比较器
1.应用在系统排序方法中
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;public class ShowComparator {public static class Student {public String name;public int id;public int age;public Student(String name, int id, int age) {this.name = name;this.id = id;this.age = age;}}// 谁id大,谁放前!public static class IdComparator implements Comparator<Student> {// 如果返回负数,认为第一个参数应该排在前面// 如果返回正数,认为第二个参数应该排在前面// 如果返回0,认为谁放前面无所谓@Overridepublic int compare(Student o1, Student o2) {if (o1.id < o2.id) {return 1;} else if (o2.id < o1.id) {return -1;} else {return 0;}}}// 谁age大,谁放前!public static class AgeComparator implements Comparator<Student> {// 如果返回负数,认为第一个参数应该排在前面// 如果返回正数,认为第二个参数应该排在前面// 如果返回0,认为谁放前面无所谓@Overridepublic int compare(Student o1, Student o2) {if (o1.age < o2.age) {return 1;} else if (o2.age < o1.age) {return -1;} else {return 0;}}}public static void printArray(int[] arr) {for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}public static void printStudents(Student[] students) {for (int i = 0; i < students.length; i++) {System.out.println(students[i].name + ", " + students[i].id + ", " + students[i].age);}}public static void main(String[] args) {int[] arr = { 8, 1, 4, 1, 6, 8, 4, 1, 5, 8, 2, 3, 0 };printArray(arr);Arrays.sort(arr);printArray(arr);Student s1 = new Student("张三", 5, 27);Student s2 = new Student("李四", 1, 17);Student s3 = new Student("王五", 4, 29);Student s4 = new Student("赵六", 3, 9);Student s5 = new Student("左七", 2, 34);Student[] students = { s1, s2, s3, s4, s5 };printStudents(students);System.out.println("=======");Arrays.sort(students, new IdComparator());printStudents(students);System.out.println("=======");ArrayList<Student> arrList = new ArrayList<>();arrList.add(s1);arrList.add(s2);arrList.add(s3);arrList.add(s4);arrList.add(s5);for (Student s : arrList) {System.out.println(s.name + ", " + s.id + ", " + s.age);}System.out.println("=======");arrList.sort(new AgeComparator());for (Student s : arrList) {System.out.println(s.name + ", " + s.id + ", " + s.age);}}}
2.应用在与排序有关的结构中优先级队列(堆)、有序表
import java.util.Comparator;
import java.util.PriorityQueue;public class ShowComparator2 {public static class MyComparator implements Comparator<Integer> {// 负,第一个参数在前// 正,第二个参数在前// 0, 谁放前都行@Overridepublic int compare(Integer o1, Integer o2) {if (o1 < o2) {return 1;} else if (o1 > o2) {return -1;} else {return 0;}}}public static class Student {public String name;public int id;public int age;public Student(String name, int id, int age) {this.name = name;this.id = id;this.age = age;}}// 谁id大,谁放前!public static class IdComparator implements Comparator<Student> {// 如果返回负数,认为第一个参数应该排在前面// 如果返回正数,认为第二个参数应该排在前面// 如果返回0,认为谁放前面无所谓@Overridepublic int compare(Student o1, Student o2) {if (o1.id < o2.id) {return 1;} else if (o2.id < o1.id) {return -1;} else {return 0;}}}public static void main(String[] args) {String str1 = "abc";String str2 = "b";System.out.println(str1.compareTo(str2));PriorityQueue<Student> heap = new PriorityQueue<>(new IdComparator());Student s1 = new Student("张三", 5, 27);Student s2 = new Student("李四", 1, 17);Student s3 = new Student("王五", 4, 29);Student s4 = new Student("赵六", 3, 9);Student s5 = new Student("左七", 2, 34);heap.add(s1);heap.add(s2);heap.add(s3);heap.add(s4);heap.add(s5);System.out.println("=========");while (!heap.isEmpty()) {Student s = heap.poll();System.out.println(s.name + ", " + s.id + ", " + s.age);}}}
五、合并多个有序链表
Leetcode原题 https://leetcode.com/problems/merge-k-sorted-lists
import java.util.Comparator;
import java.util.PriorityQueue;
// 时间复杂度 O(M*log(N))
// 测试链接:https://leetcode.cn/problems/merge-k-sorted-lists/
public class MergeKSortedLists {public static class ListNode {public int val;public ListNode next;}public static class ListNodeComparator implements Comparator<ListNode> {@Overridepublic int compare(ListNode o1, ListNode o2) {return o1.val - o2.val; }}public static ListNode mergeKLists(ListNode[] lists) {if (lists == null) {return null;}PriorityQueue<ListNode> heap = new PriorityQueue<>(new ListNodeComparator());for (int i = 0; i < lists.length; i++) {if (lists[i] != null) {heap.add(lists[i]);}}if (heap.isEmpty()) {return null;}ListNode head = heap.poll();ListNode pre = head;if (pre.next != null) {heap.add(pre.next);}while (!heap.isEmpty()) {ListNode cur = heap.poll();pre.next = cur;pre = cur;if (cur.next != null) {heap.add(cur.next);}}return head;}}
六、写在后面
欢迎关注,会经常记录一些算法学习中遇到的问题。
欢迎随时留言讨论,与君共勉,知无不答!
05.位图和比较器的简单应用相关推荐
- 比较器的简单介绍及应用
概述 在许多情况下,需要知道两个信号中哪个比较大,或者一个信号何时超出预设的电压.用运算放大器便可以容易搭建一个简单的电路实现该功能.在同相比较电路中,当输入电压超过反相电压时,输出电压将从低电平转换 ...
- PS初识 位图 矢量图 的简单理解
PS初识 位图.矢量图 的理解 PS是位图的处理软件 绝大数图片都是位图 位图放大缩小后会失真 位图的优点:位图色彩细腻 兼容性强 内存小 Ai是矢量图处理软件 矢量图:放大缩小后不会失真 使用方向: ...
- 用位运算完成大小比较
目录 只用位运算完成大小比较 写在后面 只用位运算完成大小比较 如何不用任何比较判断语句,就可以返回两个数中较大的那个 /*** @author 杨思远* @version 1.0* @title 位 ...
- 专转本就业歧视怎么消除_人工智能可以帮助消除歧视
专转本就业歧视怎么消除 Recently, a lot articles have been published covering cases in which Artificial Intellig ...
- 时间序列预测——深度好文,ARIMA是最难用的(数据预处理过程不适合工业应用),线性回归模型简单适用,预测趋势很不错,xgboost的话,不太适合趋势预测,如果数据平稳也可以使用。...
补充:https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-15-276 如果用arima的话,还不如使用随机森 ...
- 【数据结构与算法】7.位图算法、12306抢票算法
前言 本文收录于专辑:http://dwz.win/HjK,点击解锁更多数据结构与算法的知识. 你好,我是彤哥,一个每天爬二十六层楼还不忘读源码的硬核男人. 相信大家都有过抢票.刷票的经验,每年年底, ...
- java 实现中文排序,Java自定义比较器实现中文排序
compareTo 方法 compareTo()是两个字符串对象比较大小,返回一个整数值,如果调用字符串对象大,返回正整数,反之,返回负整数.相等则返回0.compareTo()是两个字符串对象按AS ...
- UWP 手绘视频创作工具技术分享系列 - 位图的绘制
UWP 手绘视频创作工具技术分享系列 - 位图的绘制 原文:UWP 手绘视频创作工具技术分享系列 - 位图的绘制 前面我们针对 SVG 的解析和绘制做了介绍,SVG 是图片的一种形式,而另一种很重要的 ...
- 如何减小电压跟随器输出电阻_补课贴 | 关于运算放大器和比较器的异同,那些你不得不知道的小知识!...
在直入正题讲解运算放大器的异同之前,小A先来帮助大家简单回顾一下运算放大器和比较器的基础知识: 比较器是一种带有反相和同相两个输入端以及一个输出端的器件,该输出端的输出电压范围一般在供电的轨到轨之间. ...
最新文章
- 动画requestAnimationFrame
- GDALWarp设置GDALWarpOptions::dfWarpMemoryLimit过大时处理失败
- 绘制简单的正太分布图
- python 插入排序算法
- 给matlab图加图注,matlab学习5-数据可视化4-gai.ppt
- NAT原理?代理服务器原理?
- 4thweek.P_problemB .poj1505copy books.二分法
- python能开发android吗_python可以开发安卓吗
- Python编写区块链
- JAVA 微信支付 native方式
- 使用 Responsive Elements 快速构建响应式网站
- [转载] 百科全说——漆浩:观手分辨五行人教您五行人的养生绝招(11-01-1011-01-11)...
- 如何使用postman带Token测试接口?
- PRINCE2认证好在哪?
- 前端工程师的第一个Flutter应用
- PJzhang:我发现一个有两个答案的数独题
- 十几减9的口算题_一年级数学《口算十几减9》教案
- 【jQWidgets】jqxGrid控件在页面上重新加载的问题
- wgs84坐标格式转换度分秒_ArcGIS坐标单位转换(米和度分秒之间是如何转换的?)...
- 微信开发系列之自定义菜单实现