1.冒泡排序
两层循环,外层循环控制轮数,内层循环做比较。
两两比较,大者交换位置,则每一轮循环结束后最大的数就会移动到最后。
时间复杂度为O(n^2);空间复杂度为O(1);
int[] nums = new int[] {4,5,1,6,8,2,3,9};
int temp = 0;
for(int i=0;i<nums.length-1;i++){
//外层循环length-1次
for (int j = 0; j < nums.length-i-1; j++) {
//外层每循环一次最后内层都会排好一个数
//所以内层循环length-1-i次
if(nums[j] > nums[j+1]){
temp = nums[j+1];
nums[j+1] = nums[j];
nums[j] = temp;
}
}
}
2.快速排序
快速排序是对冒泡排序的一种改进,借用了分治的思想:通过一轮排序将要排序的数据分成独立的两部分,其中一部分的数据比另一部分的所有数据都小,然后再对这两个小部分数据分别进行快速排序,整个排序过程可以递归进行,以此达打到所有数据都变成有序序列。
时间复杂度为O(n*logn);空间复杂度O(1)
基本步骤
- 从数列中挑出一个元素,称为“基准”(pivot)
- 重新排列数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以任意到一边)。分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归的把小于基准值元素的子数列和大于基准值元素的子数列排序。
- 递归到最底部时,数列的大小是0或者1,也就是已经排序好了。这个算法一定会结束,因为再每次的迭代中,它至少会把一个元素摆到它最后的位置去。
public static void quickSort(int[] array,int start, int end){
if(start<end){
int baseNum = array[start];//基准值
int left = start;//左指针
int right = end;//右指针
int midNum;
while(left<=right){
while(array[left]<baseNum && left<end){
left++;
}
while(array[right]<baseNum && right>start){
right--;
}
if(left<right){
middNum = array[left];
array[left] = array[right];
array[right] = midNum;
}
if(start<left){
quickSort(array, start, left);
}
if(end>right){
quickSort(array, right, end);
}
}
}
}
3.插入排序
直接插入排序(Straight Insertion Sorting) 的基本思想: 将数组中的所有元素依次跟前面已经排好的元素比较,如果选择的元素比已排序的元素值小,则交换,直到全部元素都比较过为止。
- 外层循环确定比较轮数。第一个数不用
- 确定插入数和得到已经排好序列的最后一个数的位数,内层循环每轮的循环次数,insertNum和j=i-1
public static void insertSort(int[] array){
int current;//插入数
for(int i=1;i<array.length;i++){
int j = i-1;//已排序序列的末位索引
current = array[i]
while(j>=0 && array[j]>current){//从后往前,将大于当前插入数的值往后移
array[j+1] = array[j];
j--;
}
array[j] = current;//找到位置,插入当前插入数
}
}
4.选择排序
- 遍历整个序列,将最小的数放在最前面
- 遍历剩下的序列,将最小的数放在最前面。
- 重复第二步,直到只剩下一个数。
public static void chooseSort(int[] array){
for(int i=0;i<array.length;i++){
int minNum = array[i];//最小值
int index = i;//最小值索引
for(int j=i+1;j<array.length;j++){//找到最小值
if(minNum>array[j]){
minNum = array[j];
index = j;
}
}
array[index] = array[i];//交换当前值和最小值的位置
array[i] = minNum;
}
}
5.基数排序
用于大量数,很长的数进行排序。
- 将所有的数的个位数取出,按照个位数进行排序,构成一个序列。
- 将新构成的所有的数的十位数取出,按照十位数进行排序,构成一个序列。
- 以此类推,百位数···
还不会链表
6.希尔排序
插入排序的一种高速而稳定的改进版本。
- 希尔排序时先将整个待排序的序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录依次直接插入排序。
- 简单来讲,就是将整个序列分成若干个子序列,而每个子序列就相当于数学里面周期函数的一周期,然后将第一个周期里的数据不断地跟后面每个周期相同位置的值比较,小的数据换到前面,大的数据换到后面,通过不断压缩一个周期的长度来精确。
public static void shellSort(int[] array){
int gap = array.length / 2;//进行分组(分成两周期)
for( ; gap < array.length; gap = gap /2){//缩小子序列周期
for(int j = 0; (j + gap) < array.length; j++){//重复进行
for(int k = 0; (k+gap)<array.length; k += gap){
if(array[k] > array[k+gap]){
int temp = array[k];
array[k] = array[k + gap];
array[k + gap} = temp;
}
}
}
}
}
7.归并排序
速度仅次于快速排序,内存少的时候使用,可以进行并行计算的时候使用。
- 选择相邻两个数组成一个有序序列。
- 选择相邻的两个有序序列组成一个有序序列。
- 重复第二步,直到全部组成一个有序序列。
public static void mergeSort(int[] array){
int sum = array.length;//初始序列组数
int element = 1;//初始序列元素
boolean boo = false;//为true时最后一次为不规则序列排序
while(sum > 1){//当sum等于1时完成排序
int remainder = sum % 2;//是否有落单的序列
if(remainder == 1){
boo = true;
}
int sepuence = sum / 2;
sum = remainder + sepuence;//剩余序列数
int n = 0;//排序次数
int s = element * 2;//当前两序列元素和
int[] data = new int[array.length];
int r = 0;//data指针
while(n<sum){
int left = n * s;//左指针
int right = n * s + element;//右指针
if(boo && remainder == 1 && n == sum - 1){
for(; r < array.length; r++){
data[r] = array[r];
}
}
else{
while(r < (n + 1) * s){
if((array[left] <= array[right] && left <n * s + element)|| right==(n+1)*s){
data[r] = array[left];
left++;
}
else{
data[r] = array[right];
right++;
}
r++;
}//排序
}
n++;
}
for(int i=0; i<array.length; i++){
array[i] = data[i];
}
element = s;//下一次排序时的序列元素数
}
}
8.堆排序
堆(二叉堆): 可以视为一颗完全的二叉树,完全二叉树的一个"优秀"的性质就是:除了最底层之外,每一层都是满的,这使得堆可以利用数组来表示(一般的二叉树通常用链表作为基本容器表示),每一个节点对应数组中的一个元素。
对于给定的某个节点的下标i(0开始),可以很容的计算出该节点的父节点,子节点的下标:
parent = (i+1)/2 - 1; //i的父节点下标
left = 2*(i+1) - 1; //i的左子节点下标
right = 2*(i+1); //i的右子节点下标
二叉堆一般分为两种:最大堆和最小堆。
- 分别找到i元素的左孩子和右孩子,若左孩子与右孩子中右比i元素大的,找到最大的那个元素,并且与i元素交换位子,对交换位子的那个最大元素再次重复上诉步骤。
注意:此方法成立的条件是i元素的左子树与右子树都是最大堆!!!
public static void heapSort(int[] array){
int len = array.length; //剩余未排序序列的长度
int temp = 0;
while(len > 1){
for(int i = len / 2; i > 0; i--){
if((2 * i - 1) < len && array[2 * i - 1] > array[i - 1]){
//若左子节点值大于该节点,则交换位置
temp = array[2 * i - 1];
array[2 * i - 1] = array[i - 1];
array[i - 1] = temp;
}
if(2 * i < len && array[2 * i] > array[i - 1]){
//若右子节点值大于该节点,则交换位置
temp = array[2 * i];
array[2 * i] = array[i - 1];
array[i - 1] = temp;
}
}
//此时array为最大值,交换位置到最后去
temp = array[0];
array[0] = array[len - 1];
array[len - 1] = temp;
len--;
}
}