排序后即可找出最大、最小、中位数、第N大/小的数
冒泡的算法思想:相邻元素比较,看是否满足大小关系,不满足则交换;
一次冒泡,至少一个元素移动到首/尾;n个元素,重复n次;
算法优化:某次冒泡过程,没有数据交换,则完全排序,不用执行后续冒泡操作;
第一趟:a[0]与a[1]比较,逆序则交换;然后a[1]和a[2]比较,逆序则交换...最后最大的被冒泡到最后;
public void bubbleSort(int[] arr){
int n=arr.length;
if(n<=1)
return;
for(int i=0;iarr[j+1]){
int tmp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tmp;
flag=true;//表示有数据交换
}
}
if(!flag)
break;//没有数据交换
}
}
原地排序:只涉及相邻数据交换,只需要常量级临时空间,即空间复杂度为o(1);稳定排序:只有交换才能改变元素的前后顺序。当相邻元素相等时,不做交换;时间复杂度:最好为数据已经有序,则进行一次排序即o(n);最坏为逆序,做n次排序即o(n*n);平均为o(n*n);循环次数表示时间复杂度,i循环n-1次(即n-1次比较),最坏情况下j循环n次;
一趟:从右向左找比base小的数,交换;然后从左开始找比base大的数,交换;再从右开始找...直到base左边全部比base小,右边全部比base大,然后第二趟...
如(46,79,56,38,40,84)第一趟以后变为(40,38,46,56,79,84);
缺点:源数据越有序越慢(左右两边递归);
void QuickSort(int &a, int left,int right) { //left和right表示数组最左边和最右边的值
int i, j,temp;
int lIndex= left;
int rIndex= right;
int index = a[(left + right) / 2];
while (lIndex < rIndex) {
while (a[lIndex < index]) {
++lIndex;
}
while (a[rIndex>index]) {
--rIndex;
}
if (lIndex <= rIndex) {
temp = a[lIndex];
a[lIndex] = a[rIndex];
a[rIndex] = temp;
--rIndex;
++lIndex;
}
}
If (lIndex == rIndex) {
lIndex++;
}
if (left < rIndex) {
QuickSort(a, left, lIndex - 1);
}
if (lIndex < right) {
QuickSort(a, rIndex + 1, right);
}
}
思想:元素分为未排序和已排序区间,从未排序区间取出元素按关键码插入已排序区间的合适位置,直到未排序区间没有元素;
主要方法:(直接)插入排序(增量为1),希尔排序(增量为d的子序列排序后,再排序);
第一趟:a[0]不用排序,从a[1]开始,设置它为value;j为它前面的有序去遍历,且从后向前即j--,当a[j]>value时,则将它后移一位(然后再比较a[j-1]与value)直到有一个数a[j]<=value了,则此数的后一个位置插入value;
原地排序:空间复杂度o(1);稳定排序:相同元素,后出现的插入到先出现的后边;时间复杂度:最好即已有序,o(1);最坏为逆序,o(n*n);平均为o(n*n)(插入一次为o(n),循环n次);应用广泛的为插入排序(冒泡排序有3个赋值操作即交换,而插入排序只有一个数据移动);
public void insertSort(int[] arr){
if(n<=1)
return;
int length = arr.length;
for(int i=1;i=0;--j){//查找插入的位置
if(arr[j]>value)
arr[j+1]=arr[j];//数据移动
else
break;//无序区第一个元素比有序区最后一个元素还大,则无需再比较
}
if(arr[j+1] != value)
arr[j+1]=value;//插入数据
}
}
第一趟:k=i=0,j从i+1=1开始到最后,遍历每个元素并与a[0]比较;当a[j]较小时,记录k变为j,继续遍历j,直到k是最小元素的下标j,退出j循环(即选出);比较k和i,k变了,则交换a[i]和a[k],则此时a[i]为最小;然后i++,执行第二趟遍历;不稳定;效率高(针对下标操作)
void SelectionSort(int[] arr) {
int i, j, minIndex;
int lenth=arr.length;
int index;
for (i = 0; i < lenth-1; i++) {
minIndex = i;
for (j = i + 1; j < lenth;j++) {
if (arr[j] < arr[minIndex])
minIndex = j;
}
if (minIndex != i) {
index = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = index;
}
}
}
//二叉排序树
public class TestBinaryTree {
public static void main(String[] args) {
TestBinaryTree node=new TestBinaryTree();
node.addData(4);
node.addData(7);
node.addData(98);
node.addData(46);
node.addData(4);
node.addData(2);
node.addData(45);
node.addData(84);
node.print();
}
private Node node;
//数据进来,如果是第一个数,则作为根节点,否则调用节点添加函数
public void addData(int data){
if (null==node){
node=new Node(data);
}else {
node.addNode(data);
}
}
//从根节点按照中序遍历打印二叉树
public void print(){
this.node.printNodeData();
}
}
class Node{
private int data;
private Node leftNode;
private Node rightNode;
public Node(int data) {
this.data = data;
}
/*
添加节点:判断进来的数据:
1、当前数据小,应放在节点左边
如果做节点不存在,则以当前数据新建做节点;
否则递归做节点,即继续比较做节点的数据与当前数据,判断当前数据应在左节点的哪边;
2、右边同理
*/
public void addNode(int data){
if (this.data>data){
if (null==this.leftNode){
this.leftNode=new Node(data);
}else {
this.leftNode.addNode(data);
}
}else {
if (null==this.rightNode){
this.rightNode=new Node(data);
}else {
this.rightNode.addNode(data);
}
}
}
//中序遍历:左-中-右
public void printNodeData(){
if (null!=this.leftNode){
this.leftNode.printNodeData();
}
System.out.print(this.data+" -> ");
if (null!=this.rightNode){
this.rightNode.printNodeData();
}
}
}
方法1:循环产生随机数value -> value与数组元素遍历比较 –>不同则添加进数组
//产生不重复的随机数或者随机字符
public static void getRandomNumberOrChar() {
//产生n个随机数,随机数作下标返回n个字符
String string="abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] cs=new char[10];
for (int i = 0; i < cs.length; i++) {
int random=(int) (Math.random()*string.length());
System.out.print(random+"\t");
//可以先产生不重复的随机数保存到数组(重复了就不保存),再用数组下标来指定字符;
//以下是产生了字符,再不添加重复的元素(但是被填充了空格???)
boolean flag=false;
for(int j=0;j
方法2:产生随机数 -> 存入Set集合
HashSet
方法3:将范围内值作为个数组,产生一个随机值后,将此值与数组最后一个元素交换;然后在除去最后一个元素的数组中产生第二个随机值;如此重复
public static void random(int[] range, int[] numbers) {
Random random = new Random();
int rangeIndex = -1;
for (int i = 0; i < numbers.length; i++) {
rangeIndex = random.nextInt(range.length - i);//产生范围内一个随机数作为下标
numbers[i] = range[rangeIndex ];//范围内下标处的数作为随机数数组
int temp = range[rangeIndex ];
range[rangeIndex ] = range[range.length - 1 - i];
range[range.length - 1 - i] = temp;
}
}
boolean isHuiWen(String text) {
int length = text.length();
for (int i = 0; i < length / 2; i++) {
if (text.toCharArray()[i] != text.toCharArray()[length - i - 1]) {
return false;
}
}
return true;
}
类A的a()方法调用类B的b()方法,b()方法会调用类A的某些方法,即双向调用;
计算器实例:
//同步回调,回调接口
interface CallBackInterface{
public void getResult(int a,int b,int result);
}
//A类:实现接口
class A implements CallBackInterface{
属性a,b和构造器以及调用B类的方法,以自身对象做参数
public void addA(){
new B().add(a,b,this);
}
@override
public void getResult(int a,int b,int result){
System.out.println(a+"+"+b+"="+result)
}
}
//B类:以(实现了接口的A类做参数,然后调用A类方法)
class B{
public void addB(int a,int b,CallBackInterface callbackInterface){
int result=a+b;
callBackInterface.getResult(a,b,result);
}
}
主函数:实例化A并调用addA();
异步回调:被调用方的方法在收到某种讯息或发生某种事件时(异步消息通知),才去调用对方的方法
或者说不必等被调用方法一定执行完而仍会继续执行
在addB()中的调用A类的方法之前:
try { Thread.sleep(5 * 1000); }
catch (InterruptedException e) { e.printStackTrace(); }
而addA方法需要实现多线程,即
new Thread(new Runnable(){
public void run(){
new B().add(a,b,this);
}
}).start();
1.统计数组中所有元素出现的次数/统计字符串中所有字符出现的次数(将参数换为String且转为char[],map类型为
public static void countAll(String[] stringArr) {
Map map=new HashMap();
for(String string:stringArr){
Integer integer=map.get(string);
if (integer==null) {
map.put(string, 1);
} else {
map.put(string, integer+1);
}
//找出所有包含某个字符(或子串)的字符串
for(int i=0;i
2.统计文件中某个字符串出现的次数
public static int statisticalNumber(String fileName,String str) throws Exception {
int count = 0;
BufferedReader bf = new BufferedReader(new InputStreamReader(new FileInputStream(fileName))); //构造文件输出流
String readLine ;
StringBuilder sb = new StringBuilder();
while((readLine = bf.readLine() )!= null) {
sb.append(readLine); //将数数据写入添加到缓冲字符串
}
//方式1
int a = 0;
while((a = sb.indexOf(str)) != -1) {
sb = sb.delete(a, a + str.length()); //查找字符串在缓冲字符串中的位置,查到则表示存在;删除,统计删除次数
count++;
}
//方式2:将sb再转为长String,并用str做切割符,切成字符串数组后数组长度-1即表示切割了几次,即string出现次数
count=sb.toString().split(str).length-1;
//使用正则表达式相关API
Pattern p=Pattern.compile(str);
Matcher m=p.mathcer(sb);//放在长串中匹配
while(m.find()) num++;
return count;
}
//filePath=”F:/test.txt”等价“F:\\test.txt”,第一个\是转义字符
规律:后一项=前两项之和
//递归:
void fibinacci(int n){
if(n==1||n==2) return 1;
else return fibinacci(n-1)+fibinacci(n-2);
}
//非递归之for循环/数组:
long fibinacci(long n){
long a=1;int b=1; //long[] arr=new long[n];arr[1]=arr[2]=1;
for(int i=3;i<=n;i++){
b=a+b;//arr[i]=arr[i-1]+arr[i-2];
a=b-a;
}
return b;//return arr[n-1];
}
//numrator分子,denominator分母;辗转相除法
public static void reduceToLowest(int numrator,int denominator) {
if (numrator<0||denominator<=0) {
System.out.println("非法分数");
return;
}
System.out.println("原始分数为:"+numrator+"/"+denominator);
if(numrator==denominator){
System.out.println(1);
} else {
int small=numrator
八:全排列
//第一趟:选定(第)一个字符,若干次(与它后面的)交换(当它被交换到末尾时为出口),得出基于它的全排列;然后将它复位;LinkList保存每一种排列
//第二趟:选定下一个字符
//去重排列:选定的字符与它不同的字符交换
public static void allPermutation(String str){
if(str == null || str.length() == 0)
return;
//保存所有的全排列
LinkedList
permutation(str.toCharArray(), listStr, 0);
print(listStr);//打印全排列
}
private static void permutation(char[] c, LinkedList
if(start == c.length-1)
list.add(String.valueOf(c));
else{
for(int i = start; i <= c.length-1; i++){
swap(c, i, start);//相当于: 固定第 i 个字符
permutation(c, list, start+1);//求出这种情形下的所有排列
swap(c, start, i);//复位
}
}
}
private static void swap(char[] c, int i, int j){
char tmp;
tmp = c[i];
c[i] = c[j];
c[j] = tmp;
}
private static void print(LinkedList
Collections.sort(list);//使字符串按照'字典顺序'输出
for (String str : list) {
System.out.println(str);
}
System.out.println("size:" + list.size());
}
public static void print(int row){
if (row%2==0) {
row++;//行数为奇数
}
//上本部分
for (int i = 0; i < row/2+1; i++) {
//左上角空白
for (int j = row/2+1; j >i+1; j--) {
System.out.print(" ");
}
for (int j = 0; j < 2*i+1; j++) {
if (j==0||j==2*i) {
System.out.print("*");//菱形边缘
}else {
System.out.print(" ");//菱形中间空白
}
}
System.out.println("");
}
//下半部分
for (int i = row/2+1; i < row; i++) {
//左下角空白
for (int j = 0; j
//digit为分位位数如3位为一组,每隔三个数插入一个逗号
public static String formatNumber(int digit,long value) {
StringBuffer sb=new StringBuffer(String.valueOf(value));
sb=sb.reverse();
int length=sb.length();
if (digit==0||digit>length) {
digit=length;
}
int count=0;//分位后组数
if(length%digit==0)
count=length/digit-1;
else {
count=length/digit;
}
for (int i = 0; i < count; i++) {
sb=sb.insert((i+1)*digit+i,",");//注意,添加的位置计算
}
System.out.println(sb.reverse().toString());
//return sb.reverse().toString();
return null;
}