java实现部分常见排序算法
希尔排序
选定步长,将步长间距的几个数进行比较排序,然后初始位后移一位,同样还是将步长间距的几个数进行比较排序,这样的话比较的几个数就是第一次的每个数的后一个数。然后步长就变小,同样进行前面的比较。
package example;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {5, 1, 7, 3, 1, 6, 9, 4};
shellSort(arr);
for (int i : arr) {
System.out.print(i + "\t");
}
}
private static void shellSort(int[] arr) {
//step:步长
for (int step = arr.length / 2; step > 0; step /= 2) {//步长的变化依次变小
//对一个步长区间进行比较 [step,arr.length)
for (int i = step; i < arr.length; i++) {//固定步长下的隔步长距离的比较,i+即后移一位的另一步长组的比较
int value = arr[i];
int j;
//对步长区间中具体的元素进行比较
for (j = i - step; j >= 0 && arr[j] > value; j -= step) {//固定步长的数据大的依次后移
//j为左区间的取值,j+step为右区间与左区间的对应值。
arr[j + step] = arr[j];
}
//此时step为一个负数,[j + step]为左区间上的初始交换值
arr[j + step] = value;
}
}
}
}
选择排序
和冒泡类似的两次循环,每次循环找到最小的那个数,然后下次循环,冒泡是找到最大的那个,就我个人感觉差不多。
package example;
public class SelectSort {
public static int[] selectSort(int[] arr,int n) {
for (int i = 0; i < n - 1; i++) {//外循环是趟数,每一趟就位置加一
int index = i;
int j;
// 找出最小值得元素下标
for (j = i + 1; j < n; j++) {//内循环是每一趟一个元素与其他元素的每一次比较
if (arr[j] < arr[index]) {
index = j;//每次将小的赋给index,循环结束后index就是最小的
}
}
int tmp = arr[index];
arr[index] = arr[i];
arr[i] = tmp;//将找到的数赋给外循环的那个循环位置
}
return arr;
}
public static void main(String[] args) {
int[] arr={12,3,23,2,3,2314,23,45,3425,34,53,45,4,65,7,56,786,78,34};
arr=selectSort(arr,arr.length);
for (int i : arr) {
System.out.println(i);
}
}
}
RSA案例
package example;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
public class RSADemo {
private static String src="infcn";
private static RSAPublicKey rsaPublicKey;
private static RSAPrivateKey rsaPrivateKey;
static{
KeyPairGenerator keyPairGenerator;
try {
keyPairGenerator=KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair=keyPairGenerator.generateKeyPair();
rsaPublicKey=(RSAPublicKey) keyPair.getPublic();
rsaPrivateKey=(RSAPrivateKey)keyPair.getPrivate();
System.out.println("Public key:"+Base64.encode(rsaPublicKey.getEncoded()));
System.out.println("Private key:"+Base64.encode(rsaPrivateKey.getEncoded()));
} catch (NoSuchAlgorithmException e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**公钥加密,私钥解密
* @author 29284
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static void pubEn2PriDe() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
//公钥加密
X509EncodedKeySpec x509EncodedKeySpec=new X509EncodedKeySpec(rsaPublicKey.getEncoded());
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
PublicKey publicKey=keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher=Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result=cipher.doFinal(src.getBytes());
System.out.println("公钥加密,私钥解密--加密:"+Base64.encode(result));
//私钥解密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec=new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
keyFactory=KeyFactory.getInstance("RSA");
PrivateKey privateKey=keyFactory.generatePrivate(pkcs8EncodedKeySpec);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
result=cipher.doFinal(result);
System.out.println("公钥加密,私钥解密--解密:"+new String(result));
}
/**
* 私钥加密,公钥解密
* @author jijs
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
* @throws NoSuchPaddingException
* @throws InvalidKeyException
* @throws BadPaddingException
* @throws IllegalBlockSizeException
*/
public static void priEn2PubDe() throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
//私钥加密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("私钥加密,公钥解密 --加密 : " + Base64.encode(result));
//公钥解密
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
result = cipher.doFinal(result);
System.out.println("私钥加密,公钥解密 --解密: " + new String(result));
}
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
pubEn2PriDe();
priEn2PubDe();
}
}
快排
使用快速排序,首先选取数组中某个元素t,然后将其他元素重新排列,使数组中所有在t前面的元素都小于或等于t,所有在t后面的元素都大于或等于t。这里我们使用最简单的选择策略:每次都选取数组第一个元素当做中轴(即前面的t),然后同时从左右开始扫描,左边找到一个比中轴大的,右边找到一个比中轴小的,然后交换两个元素的位置。,然后就是每次都进行同样的过程,这就类似与分治,左边的一部分,右边的一部分。
public static int partition(int[] arr,int left,int right){
int pivot = arr[left];
while(left < right){
while(left<right && arr[right] >= pivot)
right--;
arr[left] = arr[right];
while(left < right && arr[left]<= pivot)
left++;
arr[right] = arr[left];
}
arr[left] = pivot;
return left;
}
插入排序
插入排序就是首先认为数组已经是有序了的,先找到一个数放入,然后依次将下一个数与他们进行比较找到合适的位置插进去,每次插入后数组都是有序的。
package example;
public class InsertSort{
public static int[] insertSort(int[] arr)
{
for (int i = 1; i < arr.length; i++)//每次选择一个插入
{
int k = arr[i];//k用来代替arr【i】进行大小判断
int j = i;//j内循环用来判断当前位与前一位的大小
while (j > 0 && arr[j - 1] > k)//如果要插入的元素的前一位比他大则前一位后移
{
arr[j] = arr[j - 1];//元素后移
j--;//变量前移
}
arr[j] = k;//k插入到这
}
return arr;
}
public static void main(String[] args) {
int[] arr={1,23,3,44,5,4,56,57,6,7,568,67,89,67,986,7,6,79,23,86,78,6,8};
arr=insertSort(arr);
for (int i : arr) {
System.out.println(i);
}
}
}
冒泡排序
这个最简单就没得什么说的了
@Test
void test15() {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(10);
list.add(5);
list.add(17);
list.add(6);
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j <list.size()-i-1; j++) {
if (list.get(j).compareTo(list.get(j+1))>0) {
Integer temp = list.get(j);
list.set(j,list.get(j+1));
list.set(j+1,temp);
}
}
}
list.stream().forEach(e-> System.out.println(e));
}
线程池
package example.testForJava;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class threadPool {
public static void main(String[] args) {
//线程池容量为5,最大可扩展到10
/*保持200表示线程没有任务执行时最多保持多久时间会终止。
默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,
直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,
如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。
unit为前一参数的单位*/
//等待队列
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(5));
for (int i = 0; i < 15; i++) {
MyTask myTask = new MyTask(i);
executor.execute(myTask);
System.out.println("thread pool num " + executor.getPoolSize() + " queue num " + executor.getQueue().size() + " already complected num " + executor.getCompletedTaskCount());
}
executor.shutdown();
}
}
基数排序
基数排序介绍
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,它是通过键值的各个位的值,将要排序的元素分配至某些“桶”中,达到排序的作用
基数排序法是属于稳定性的排序,基数排序法是效率高的稳定性排序法。
LSD
排序过程就是先将一组数以个位数的顺序排列后,再将得到的序列按十位数的顺序排列,再依次往高位移动,最后得到数列。适用与位数较小的序列。
MSD
位数多的话用次方法,由高位开始,但是分配后并不马上合并回一个数组中,而是在每个桶中建立子桶,每个桶中按下一位分配到桶,在进行完最低位数的分配后再合并回单一的数组中
//LSD
public class RadixSort {
public static void main(String[] args) {
int arr[]={53, 3, 542, 748, 14, 214};
radixSort(arr);
}
public static void radixSort(int[] arr){
//先求出数组中的最大的数
int max=arr[0];
for(int i=1;i<arr.length;i++){
if(arr[i]>max){
max=arr[i];
}
}
//得到最大数是几位数
int maxLength=(max+"").length();
//定义一个二维数组,表示10个桶,每个桶就是一个数组
//为了在放入数时防止数据溢出,我们每个桶的大小为arr.length,即每个桶最多放进数组里的所有元素
int[][] bucket=new int[10][arr.length];
//定义一个一维数组来记录各个桶的每次放入的数据个数
int[] bucketElementCount=new int[10];
for(int i=0,n=1;i<maxLength;i++,n*=10){
//对每个元素的对应位进行处理
for(int j=0;j<arr.length;j++){
//取出每个元素的对应位的值
int digiOfElement=arr[j]/n%10;
//放入到对应的桶中
bucket[digiOfElement][bucketElementCount[digiOfElement]]=arr[j];
bucketElementCount[digiOfElement]++;
}
//按照这个桶的顺序即一维数组的下标一次取出数据放入原来数组
int index=0;
//遍历每一桶,并将桶中数据放入到原数组
for(int k=0;k<bucketElementCount.length;k++){
//如果桶中有数据,才放入原来数组
if(bucketElementCount[k]!=0){
for(int m=0;m<bucketElementCount[k];m++){
arr[index++]=bucket[k][m];
}
}
//每一轮处理后,需将bucketElementCount[k]=0
bucketElementCount[k]=0;
}
System.out.println("第"+(i+1)+"轮,对个位数的排序处理 arr="+ Arrays.toString(arr));
}
}
}
合并排序(归并排序)使用分治思想
每次就将一个大数组分成两个小数组,然后递归调用,直到最后只剩一个数,就是排好序的,然后就递归回去,每次将已经排好序的两个小数组合并成一个大数组。分后的图就类似于一个二叉树。
void Copy(int a[],int b[],int left,int right)
{
//将b[0]至b[right-left+1]拷贝到a[left]至a[right]
int size=right-left+1;
for(int i=0; i<size; i++) {
a[left++]=b[i];
}
}
void Merge(int a[],int b[],int left,int i,int right)
{
//合并有序数组a[left:i],a[i+1:right]到b,得到新的有序数组b
int a1cout=left, //指向第一个数组开头
a1end=i, //指向第一个数组结尾
a2cout=i+1, //指向第二个数组开头
a2end=right, //指向第二个数组结尾
bcout=0; //指向b中的元素
for(int j=0; j<right-left+1; j++) {
//执行right-left+1次循环,数组
if(a1cout>a1end) {
b[bcout++]=a[a2cout++];
continue;
} //如果第一个数组结束,拷贝第二个数组的元素到b
if(a2cout>a2end) {
b[bcout++]=a[a1cout++];
continue;
} //如果第二个数组结束,拷贝第一个数组的元素到b
if(a[a1cout]<a[a2cout]) {
b[bcout++]=a[a1cout++];
continue;
} //如果两个数组都没结束,比较元素大小,把较小的放入b
else {
b[bcout++]=a[a2cout++];
continue;
}
}
}
void MergeSort(int a[],int left,int right)
{
//对数组a[left:right]进行合并排序
int *b=new int[right-left+1];
if(left<right) {
int i=(left+right)/2;//取中点
MergeSort(a,left,i);//左半边进行合并排序
MergeSort(a,i+1,right);//右半边进行合并排序
Merge(a,b,left,i,right);//左右合并到b中
Copy(a,b,left,right);//从b拷贝回来
}
}
int main()
{
int n=10;
int a[]={5,8,2,9,4,6,3,1,10,7};
MergeSort( a, 0, n-1);
for(int j=0; j<n; j++) {
cout<<" "<<a[j];
}
return 1;
}