插入排序
1. 直接插入排序
直接插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。
public static void Insertsort(int a[], int n) {
int i, j;
for (i = 1; i < n; i++) {
if (a[i] < a[i - 1]) {
int temp = a[i];
// 将比a[i]大的值右移
for (j = i - 1; j >= 0 && a[j] > temp; j--) {
a[j + 1] = a[j];
}
// 将值插入到比其小的数后
a[j + 1] = temp;
}
}
}
2. 希尔排序
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有较大提高。
void shellsort2(int a[], int n)
{
int j, gap;
for (gap = n / 2; gap > 0; gap /= 2)
for (j = gap; j < n; j++)//从数组第gap个元素开始
if (a[j] < a[j - gap])//每个元素与自己组内的数据进行直接插入排序
{
int temp = a[j];
int k = j - gap;
while (k >= 0 && a[k] > temp)
{
a[k + gap] = a[k];
k -= gap;
}
a[k + gap] = temp;
}
}
选择排序
1. 直接选择排序
直接选择排序和直接插入排序类似,都将数据分为有序区和无序区。所不同的是直接插入排序是将无序区的第一个元素直接插入到有序区以形成一个更大的有序区,而直接选择排序是从无序区选一个最小的元素直接放到有序区的最后。
public static void Selectsort(int a[], int n) {
int i, j, nMinIndex;
for (i = 0; i < n; i++) {
nMinIndex = i;
// 找最小元素的位置
for (j = i + 1; j < n; j++) {
if (a[j] < a[nMinIndex]) {
nMinIndex = j;
}
}
// 将这个元素放到无序区的开头
int temp = a[nMinIndex];
a[nMinIndex] = a[i];
a[i] = temp;
}
}
2. 堆排序
public class HeapSort {
public static void main(String[] args) {
int[] array = {51, 46, 20, 18, 65, 97, 82, 30, 77, 50,100 };
HeapSort.sort(array);
System.out.println("排序后数组:" + Arrays.toString(array));
}
public static void sort(int[] a) {
// 循环建立初始堆,若父节点索引为i,那么左节点的索引为i*2+1,即左节点为a.length时,其父节点应当为(a.length-1)/2
// 遍历存在子节点的父节点
for (int i = (a.length - 1) / 2; i >= 0; i--) {
adjustHeap(a, i, a.length - 1);
}
// 进行n-1次循环完成排序
for (int i = a.length - 1; i > 0; i--) {
// 最后一个元素和第一个元素进行交换
int temp = a[i];
a[i] = a[0];
a[0] = temp;
adjustHeap(a, 0, i - 1);
}
}
// 将数组转换为大根堆,大根堆的根节点为数组中的最大值 ,length为数组的最大脚标
public static void adjustHeap(int[] a, int parent, int length) {
int temp = a[parent]; // 父节点的值
int child = 2 * parent + 1; // 左子节点的索引
while (child < length) {// 判断左节点是否为最大索引
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (child + 1 <= length && a[child] < a[child + 1]) {
child ++;// 将左子节点转换为右子节点
}
// 当父节点的值直接大于子节点的值时,直接退出
if (temp > a[child])
break;
// 将子节点的值赋值给父节点
a[parent] = a[child];
// 选取子节点的左子节点继续向下筛选
parent = child;
child = 2 * parent + 1;
}
// 若发生交换,此时parent代表子节点索引,没有发生交换,此时parent仍旧代表父节点索引
a[parent] = temp;
}
}
交换排序
1. 冒泡排序
设数组长度为N。
1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。
2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
3.N=N-1,如果N不为0就重复前面二步,否则排序完成。
void BubbleSort1(int a[], int n)
{
int i, j;
for (i = 0; i < n; i++)
for (j = 1; j < n - i; j++)
if (a[j - 1] > a[j])
Swap(a[j - 1], a[j]);
}
2. 快速排序
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
public static void quickSort(int s[], int l, int r) {
if (l < r) {
int i = l, j = r, temp = s[l];
while (i < j) {
// 从右向左找第一个小于x的数
while (i < j && s[j] >= temp) {
j--;
}
if (i < j) {
s[i++] = s[j];
}
// 从左向右找第一个大于等于x的数
while (i < j && s[i] < temp) {
i++;
}
if (i < j) {
s[j--] = s[i];
}
}
s[i] = temp;
// 递归调用
quickSort(s, l, i - 1);
quickSort(s, i + 1, r);
}
}
归并排序
归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?
可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
package suanfa;
public class MergeSort {
public static void main(String args[]) {
int a[] = { 2, 4, 11, 8, 1, 3, 5, 9 };
int temp[] = new int[11];
mergesort(a, 0, a.length - 1, temp);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]);
}
}
public static void mergesort(int[] a, int first, int last, int[] temp) {
if (first < last) {
int mid = (first + last) / 2;
mergesort(a, first, mid, temp); // 左边有序
mergesort(a, mid + 1, last, temp); // 右边有序
mergearray(a, first, mid, last, temp); // 再将二个有序数列合并
}
}
// 数组的两段排序
public static void mergearray(int[] a, int first, int mid, int last,
int temp[]) {
int f = first, j = mid + 1;
int m = mid, l = last;
int k = 0;
while (f <= m && j <= l) {
if (a[f] <= a[j])
temp[k++] = a[f++];
else
temp[k++] = a[j++];
}
while (f <= m)
temp[k++] = a[f++];
while (j <= l)
temp[k++] = a[j++];
for (f = 0; f < k; f++)
a[first + f] = temp[f];
}
}
查找,排序复杂度
一、查找
1)线性查找:O(n);
2)二分查找:O(logn);
3)二叉排序树查找:O(logn);
二、排序
时间复杂度:
O(N):计数排序,基数排序
O(n2) :插入排序,冒泡排序,选择排序
O(N*logN):归并排序,快速排序,堆排序,希尔排序
空间复杂度:
O(1):插入排序,冒泡排序,选择排序,堆排序,希尔排序
O(logN)~O(N):快速排序
O(N):归并排序
O(M):计数排序,基数排序