数据结构排序算法的概念是从网上抄录的:
基本概念:
1、 排序:按照一定的关键字,将一个序列排列成想要得到的一个新的序列。
2、 内部排序和外部排序:整个排序过程完全在内存中进行,叫做内部排序。数据量较大需要借助外部存储设备才能完成,叫做外部排序。
3、 主关键字和此关键字:
4、 排序的稳定性:对于相同的元素来说,在排序之前和之后的书讯是一样的,那么这种排序就是稳定的排序,如果顺序发生了变化,那么就是不稳定排序。
插入类排序:
(一) 思想:在一个已经排好序的序列中,将未被排进的元素按照原先的规定插入到指定位置。
(二) 分类:
1、 直接插入排序:
① 思想:最基本的插入排序,将第i个插入到前i-1个中的适当位置。
② 时间复杂度:T(n) = O(n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。循环条件while(r[0].key < r[j].key)保证的。
⑤ 程序:
/**
* 直接插入排序:
* 1.从第一个元素开始,该元素可以认为已经被排序
* 2.取出下一个元素,在已经排序的元素序列中从后向前扫描
* 3.如果该元素小于前面的元素(已排序),则依次与前面元素进行比较如果小于则交换,直到找到大于该元素的就则停止;
* 4.如果该元素大于前面的元素(已排序),则重复步骤2 5.重复步骤2~4 直到所有元素都排好序 。
*
* @param a
*/
public static void insert(int[] a) {
for (int i = 1; i < a.length; i++) {
int key = a[i];
for (int j = i - 1; j >= 0; j--) {
if (key < a[j]) {
int temp = a[j];
a[j] = key;
a[i] = temp;
i = j;
}
}
}
}
2、 折半插入排序:
① 思想:因为是已经确定了前部分是有序序列,所以在查找插入位置的时候可以用折半查找的方法进行查找,提高效率。
② 时间复杂度:比较时的时间减为O(n㏒n),但是移动元素的时间耗费未变,所以总是得时间复杂度还是O(n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。
⑤ 程序:
/**
* 折半插入排序:
* 在将一个新元素插入已排好序的数组的过程中,寻找插入点时, 将待插入区域的首元素设置为a[low],末元素设置为a[high],
* 比较时将待插入元素与a[m],其中m=(low+high)/2相比较,如果比参考元素大,
* 则选择a[low]到a[m-1]为新的插入区域(即high=m-1), 否则选择a[m+1]到a[high]为新的插入区域(即low=m+1),
* 如此直至low<=high不成立,即将此位置之后所有元素后移一位, 并将新元素插入a[high+1]。
*
* @param a
*/
public static void binaryInsert(int[] a) {
// {1, 5, 5, 3, 4, 3,2}
for (int i = 1; i < a.length; i++) {
int key = a[i];
int low = 0;
int high = i - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (key < a[mid]) {
high = mid - 1;
} else {
low = mid + 1;
}
}
System.out.println("low:" + low + ",high:" + high + ",i:" + i
+ ",key:" + key);
for (int j = i; j > high + 1; j--) {
a[j] = a[j - 1];
}
a[high + 1] = key;
}
}
3、shell排序
交换类排序:
(一) 思想:通过交换逆序元素进行排序的方法。
(二) 分类:
1、 冒泡排序:
① 思想:反复扫描待排序序列,在扫描的过程中顺次比较相邻的两个元素的大小,若逆序就交换位置。第一趟,从第一个数据开始,比较相邻的两个数据,(以升序为例)如果大就交换,得到一个最大数据在末尾;然后进行第二趟,只扫描前n-1个元素,得到次大的放在倒数第二位。以此类推,最后得到升序序列。如果在扫描过程中,发现没有交换,说明已经排好序列,直接终止扫描。所以最多进行n-1趟扫描。
② 时间复杂度:T(n) = O(n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:稳定排序。
⑤ 程序:
/**
* 冒泡排序:
* 依次比较相邻的两个数,将小数放在前面,大数放在后面。 即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。
* 然后比较第2个数和第3个数,将小数放前,大数放后,如此继续, 直至比较最后两个数,将小数放前,大数放后。 至此第一趟结束,将最大的数放到了最后。
* 依次执行以上步骤a.leng-1次,排序完成。
*
* @param a
*/
public static void bubble(int[] a) {
// {1, 5, 5, 3, 4, 3,2}
for (int i = 1; i < a.length; i++) {
for (int j = 0; j < a.length - i; j++) {
if (a[j + 1] < a[j]) {
int temp = a[j + 1];
a[j + 1] = a[j];
a[j] = temp;
}
}
}
}
2、 快速排序:
① 思想:冒泡排序一次只能消除一个逆序,为了能一次消除多个逆序,采用快速排序。以一个关键字为轴,从左从右依次与其进行对比,然后交换,第一趟结束后,可以把序列分为两个子序列,然后再分段进行快速排序,达到高效。
② 时间复杂度:平均T(n) = O(n㏒n),最坏O(n)。
③ 空间复杂度:S(n) = O(㏒n)。
④ 稳定性:不稳定排序。{3, 2, 2}
⑤ 程序:
/**
* 快速排序:
* 一趟快速排序的算法是:
* 1)设置两个变量l、h,排序开始的时候:l=0,h=N-1;
* 2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
* 3)从j开始向前搜索,即由后开始向前搜索,找到第一个小于key的值A[j],将A[j]和A[i]互换,然后h--;
* 4)从i开始向后搜索,即由前开始向后搜索,找到第一个大于key的A[i],将A[i]和A[j]互换,然后l++;
* 5)重复第3、4步,直到l==h
*
* @param a
*/
public static void quick(int[] a, int l, int h) {
int low = l;
int high = h;
int key = a[low];
while (low < high) {
//从后往前找
while (low < high && key < a[high]) {
high--;
}
if (low < high) {
int temp = a[high];
a[high] = a[low];
a[low] = temp;
low++;
}
//从前往后找
while (low < high && key > a[low]) {
low++;
}
if (low < high) {
int temp = a[high];
a[high] = a[low];
a[low] = temp;
high--;
}
}
if (low > l) {
quick(a, l, low-1);
}
if (high < h) {
quick(a, high+1, h);
}
}
选择类排序:
(一) 思想:每一趟在n – i + 1 ( i = 1,2, … , n - 1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。
(二) 分类:
1、 简单选择排序:
① 思想:第一趟时,从第一个记录开始,通过n – 1次关键字的比较,从n个记录中选出关键字最小的记录,并和第一个记录进行交换。第二趟从第二个记录开始,选择最小的和第二个记录交换。以此类推,直至全部排序完毕。
② 时间复杂度:T(n) = O(n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序,{3, 3, 2}。
⑤ 程序:
/**
* 选择排序:
* 在第一趟遍历N个数据,找出其中最小的数值与第一个元素交换,
* 第二趟遍历剩下的N-1个数据,找出其中最小的数值与第二个元素交换......
* 第N-1趟遍历剩下的2个数据,找出其中最小的数值与第N-1个元素交换,
* 至此选择排序完成。
* @param a
*/
public static void selectSort(int[] a) {
//{ 1, 5, 5, 3, 4, 3, 2 };
for(int i=1; i<a.length; i++) {
int flag = i-1;
for(int j=i; j<a.length; j++) {
if(a[flag] > a[j]) {
flag = j;
}
}
if(flag != i-1) {
int temp = a[flag];
a[flag] = a[i-1];
a[i-1] = temp;
}
toString(a);
}
}
3、 堆排序:
① 思想:把待排序记录的关键字存放在数组r[1…n]中,将r看成是一刻完全二叉树的顺序表示,每个节点表示一个记录,第一个记录r[1]作为二叉树的根,一下个记录r[2…n]依次逐层从左到右顺序排列,任意节点r[i]的左孩子是r[2i],右孩子是r[2i+1],双亲是r[i/2向下取整]。然后对这棵完全二叉树进行调整建堆。
② 时间复杂度:T(n) = O(n㏒n)。
③ 空间复杂度:S(n) = O(1)。
④ 稳定性:不稳定排序。{5, 5, 3}
转载于:https://blog.51cto.com/7835295/1640319