直接插入排序
int a[] ={2,4,5,6,3,1,7,8,3};
//排序算法:稳定的算法,不会改变相同数字在数组的前后顺序;
//复杂度为O(n^2);
/*
快速排序:直接插入排序(Insertion Sort)的基本思想是:
每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,
直到全部记录插入完成为止:时间复杂度为:O(1+2+3+...+(n-1)) = O(n^2)
*/
Insertsort(a);
for(int element : a){
System.out.print(element+" ");
}
private void Insertsort(int[] a) {
int i , j ;
for (i = 1; i < a.length; i++) {
for ( j = i-1; j >= 0 && a[j] > a[j+1] ; j--) {
int temp = a[j] ;
a[j] = a[j+1] ;
a[j+1] = temp;
}
}
}
数组中的相同数字的总个数
/**
* 有序数组中的相同数字的个数,时间复杂度为O(n);
*/
private void equalAll() {
int a[] = {2,2,2,3,4,5,5,6,6,6,7};
int count = 0 ;
//标示符,用于标示上次循环是否相同;
boolean flag = false ;
for (int i = 0; i < a.length -1 ; i++) {
if (a[i] == a[i+1]){
flag = true ;
count ++ ;
}else {
if (flag){
flag = false ;
count++ ;
}
}
}
System.out.println("相同的元素总共有:" + count);
}
去重排序
/**
* 去重,使用集合的方式,时间复杂度为O(n^2);
*/
private void setAndList() {
int[] nums = { 5, 6, 6, 6, 8, 8, 8 , 7 , 9 , 9 , 9 };
List<Integer> numList = new ArrayList<Integer>();
for (int i : nums){
if (!numList.contains(i)){
numList.add(i);
}
}
System.out.println(numList);
}
/**
* 使用数组的复制也可以
* 时间复杂度为O(n^2)
*/
private void setAndList2() {
int arr[] ={2,4,5,6,3,1,7,8,3, 9 , 9 };
//用来记录去除重复之后的数组长度和给临时数组作为下标索引
int t = 0;
//临时数组
int[] tempArr = new int[arr.length];
//遍历原数组
for(int i = 0; i < arr.length; i++){
//声明一个标记,并每次重置
boolean isTrue = true;
//内层循环将原数组的元素逐个对比
for(int j=i+1;j<arr.length;j++){
//如果发现有重复元素,改变标记状态并结束当次内层循环
if(arr[i]==arr[j]){
isTrue = false;
break;
}
}
//判断标记是否被改变,如果没被改变就是没有重复元素
if(isTrue){
//没有元素就将原数组的元素赋给临时数组
tempArr[t] = arr[i];
//走到这里证明当前元素没有重复,那么记录自增
t++;
}
}
//声明需要返回的数组,这个才是去重后的数组
int[] newArr = new int[t];
//用arraycopy方法将刚才去重的数组拷贝到新数组并返回
/**
* public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
src:源数组; srcPos:源数组要复制的起始位置;
dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度。
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
*/
System.arraycopy(tempArr,0,newArr,0,t);
for(int element : newArr){
System.out.print(element+" 我是 ");
}
}
希尔排序:时间复杂度O(n^1.3),注意是不稳定的排序方式
/**
* 希尔排序:先分组在直接插入排,由于分组以后数据基本有序,使用直接插入排序销效率最高
* 通常分组n = 2, 或者3 ,时间复杂度大量数据下为 n ^1.3
*/
private void shellSort() {
int a[] = {49, 38, 65, 97, 26, 13, 27, 49, 55, 4};
int i , j ,gap ;
for ( gap = a.length / 2; gap > 0 ; gap /= 2) {
for ( i = gap; i < a.length ; i++) {
for (j = i - gap ; j >= 0 && a[j] > a[j + gap] ; j-=gap) {
int temp = a[j];
a[j] = a[j+gap];
a[j+gap] = temp ;
}
}
}
for(int element : a){
System.out.print(element+" heihie ");
}
}
冒泡排序:时间复杂度为O(n^2)
/**
* 冒泡排序
* 讲设数组长度为N。
1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。
2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
3.N=N-1,如果N不为0就重复前面二步,否则排序完成。
*/
private void BuddleSort() {
int a[] = {2,1,4,3,5,2,4,7,6,8} ;
int i , j ;
for ( i = 0; i < a.length; i++) {
for (j = 1; j < a.length - i; j++) {
if (a[j -1] > a[j]){
int temp = a[j] ;
a[j] = a[j - 1];
a[j - 1] = temp ;
}
}
}
printSort(a);
}
private void printSort(int[] a) {
for(int emplete: a){
System.out.print("---" + emplete);
}
}
- 但当其后的数组已经有序的情况下,该方法依然会执行下去,降低效率,为此我们可以改善为:
/**
* 从大到小排序,如果后面的已经有序的话就不用再排序了
*/
private void BuddleSort2() {
int i, j ;
int num[] = {2,1,3,4,5,6,7};
//初始化标示用于对数组是否交换
boolean flag = true ;
//判断上次交换是否有改变,不改变则其后的值均有序了,跳出循环,不在遍历
for (i = 0; i < num.length && flag; i++) {
flag = false ;
for (j = num.length - 1 ; j > i ; j--) {
if (num[j - 1] > num[j]){
int temp = num[j-1] ;
num[j-1] = num[j] ;
num[j] = temp ;
//交换以后将flag设置为true,让循环继续
flag = true ;
}
}
}
}
简单选择排序:
- 不稳定,时间复杂度为O(n^2),但由于交换次数为n-1,性能上优于冒泡排序
/**
* 选择排序,不稳定的排序方法
* 每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕
* 由于每次选择仅考虑某一位置上的数据情况,可能会破坏之前数据的相对位置,因此它是一种不稳定的排序方法。
*/
private void choiceSort() {
int num[] = {2,1,3,4,8,6,5,7};
int i , j , min;
for (i = 0; i < num.length - 1; i++) {
//将初始化的i的值作为min的标示,后续判断是否相等,不相等就交换两个值
min = i ;
for ( j = i + 1; j < num.length; j++) {
//如果min后面的值有小于他的,就将其数组中的索引赋值给min,在比较,知道找到最小的索引值
if (num[min] > num[j]){
min = j ;
}
}
if (min != i){
//交换位置
int temp = num[i];
num[i] = num[min];
num[min] = temp ;
}
}
printSort(num);
}
快速排序:时间复杂度为O(nlogn)
- 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序
/**
*
* @param numbers 带排序数组
* @param low 开始位置
* @param high 结束位置
*/
public void quickSort(int[] numbers,int low,int high)
{
if(low < high) {
int middle = quecklySort(numbers,low,high); //将numbers数组进行一分为二
quickSort(numbers, low, middle-1); //对低字段表进行递归排序
quickSort(numbers, middle+1, high); //对高字段表进行递归排序
}
}
/**
* 快速排序:
* 把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;
* 交换了以后再和小的那端比,比它小不交换,比他大交换。
* 这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,
* 然后再用分治法,分别对这两个独立的数组进行排序
*
* * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
*
* @param numbers 带查找数组
* @param low 开始位置
* @param high 结束位置
* @return 中轴所在位置
*/
private int quecklySort(int[] numbers , int low , int high) {
int temp = numbers[low]; //数组的第一个作为中轴
while(low < high)
{
while(low < high && numbers[high] >=temp)//从右向左找第一个
//小于等于基准值得index
{
high--;
}
numbers[low] = numbers[high];//比中轴小的记录移到低端
while(low < high && numbers[low] <= temp)//从左向右找第一个
//大于等于基准值的index
{
low++;
}
numbers[high] = numbers[low] ; //比中轴大的记录移到高端
}
numbers[low] = temp ; //中轴记录到尾
return low ; // 返回中轴的位置
}
//调取的方式
//快速排序
int number[] = {2,1,4,5,6,3,4,2,6,8};
quickSort(number, 0 , number.length - 1) ;
System.out.println("我是快速排序:");
for (int i : number) {
Log.e("shiqiang" , i + "--");
}
归并排序,算法复杂度O(n logn) ,稳定
将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取。
工作原理:
1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2、设定两个指针,最初位置分别为两个已经排序序列的起始位置
3、比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4、重复步骤3直到某一指针达到序列尾
5、将另一序列剩下的所有元素直接复制到合并序列尾
public class MergeSortTest {
public static void main(String[] args) {
int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
print(data);
mergeSort(data);
System.out.println("排序后的数组:");
print(data);
}
public static void mergeSort(int[] data) {
sort(data, 0, data.length - 1);
}
public static void sort(int[] data, int left, int right) {
if (left >= right)
return;
// 找出中间索引
int center = (left + right) / 2;
// 对左边数组进行递归
sort(data, left, center);
// 对右边数组进行递归
sort(data, center + 1, right);
// 合并
merge(data, left, center, right);
print(data);
}
/**
* 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序
*
* @param data
* 数组对象
* @param left
* 左数组的第一个元素的索引
* @param center
* 左数组的最后一个元素的索引,center+1是右数组第一个元素的索引
* @param right
* 右数组最后一个元素的索引
*/
public static void merge(int[] data, int left, int center, int right) {
// 临时数组
int[] tmpArr = new int[data.length];
// 右数组第一个元素索引
int mid = center + 1;
// third 记录临时数组的索引
int third = left;
// 缓存左数组第一个元素的索引
int tmp = left;
while (left <= center && mid <= right) {
// 从两个数组中取出最小的放入临时数组
if (data[left] <= data[mid]) {
tmpArr[third++] = data[left++];
} else {
tmpArr[third++] = data[mid++];
}
}
// 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)
while (mid <= right) {
tmpArr[third++] = data[mid++];
}
while (left <= center) {
tmpArr[third++] = data[left++];
}
// 将临时数组中的内容拷贝回原数组中
// (原left-right范围的内容被复制回原数组)
while (tmp <= right) {
data[tmp] = tmpArr[tmp++];
}
}
public static void print(int[] data) {
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
堆排序: 复杂度O(nlgn)
- 堆是一种重要的数据结构,为一棵完全二叉树, 底层如果用数组存储数据的话,假设某个元素为序号为i(Java数组从0开始,i为0到n-1),如果它有左子树,那么左子树的位置是2i+1,如果有右子树,右子树的位置是2i+2,如果有父节点,父节点的位置是(n-1)/2取整。分为最大堆和最小堆,最大堆的任意子树根节点不小于任意子结点,最小堆的根节点不大于任意子结点。所谓堆排序就是利用堆这种数据结构来对数组排序,我们使用的是最大堆。处理的思想和冒泡排序,选择排序非常的类似,一层层封顶,只是最大元素的选取使用了最大堆。最大堆的最大元素一定在第0位置,构建好堆之后,交换0位置元素与顶即可。堆排序为原位排序(空间小), 且最坏运行时间是O(nlgn),是渐进最优的比较排序算法。
堆排序的大概步骤如下:
- 构建最大堆。
- 选择顶,并与第0位置元素交换
- 由于步骤2的的交换可能破环了最大堆的性质,第0不再是最大元素,需要调用maxHeap调整堆(沉降法),如果需要重复步骤2
public class HeapSort {
public static void main(String[] args) {
int[] array = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3 };
System.out.println("Before heap:");
ArrayUtils.printArray(array);
heapSort(array);
System.out.println("After heap sort:");
ArrayUtils.printArray(array);
}
public static void heapSort(int[] array) {
if (array == null || array.length <= 1) {
return;
}
buildMaxHeap(array);
for (int i = array.length - 1; i >= 1; i--) {
ArrayUtils.exchangeElements(array, 0, i);
maxHeap(array, i, 0);
}
}
private static void buildMaxHeap(int[] array) {
if (array == null || array.length <= 1) {
return;
}
int half = array.length / 2;
for (int i = half; i >= 0; i--) {
maxHeap(array, array.length, i);
}
}
private static void maxHeap(int[] array, int heapSize, int index) {
int left = index * 2 + 1;
int right = index * 2 + 2;
int largest = index;
if (left < heapSize && array[left] > array[index]) {
largest = left;
}
if (right < heapSize && array[right] > array[largest]) {
largest = right;
}
if (index != largest) {
ArrayUtils.exchangeElements(array, index, largest);
maxHeap(array, heapSize, largest);
}
}
}
工具类
public class ArrayUtils {
public static void printArray(int[] array) {
System.out.print("{");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]);
if (i < array.length - 1) {
System.out.print(", ");
}
}
System.out.println("}");
}
public static void exchangeElements(int[] array, int index1, int index2) {
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
}