目录
第 41 天: 顺序查找与折半查找
顺序查找:
设置第一个位置data[0]的值为哨兵,从后往前遍历,如果一直遍历到哨兵的位置说明未找到该元素。
顺序查找时间复杂度为 O(n).
二分查找:
前提是一个有序序列,设置一个左指针left,初始值为最左边下标,右指针right,初始值为最右边下标。计算mid=(left+right)/2;如果data[mid].key等于要查找的值则返回,如果data[mid].key大于查找值,说明要查找的值在左侧,修改右指针,right=mid-1;如果data[mid].key小于查找值,说明要查找的值在右边,修改左指针,left=mid+1.
二分查找的时间复杂度为O(log n)。
代码:
package xjx;
public class DataArray {
class DataNode {
int key;
String content;
DataNode(int paraKey, String paraContent) {
key = paraKey;
content = paraContent;
}
public String toString() {
return "(" + key + ", " + content + ") ";
}
}
DataNode[] data;
int length;
public DataArray(int[] paraKeyArray, String[] paraContentArray) {
length = paraKeyArray.length;
data = new DataNode[length];
for (int i = 0; i < length; i++) {
data[i] = new DataNode(paraKeyArray[i], paraContentArray[i]);
}
}
public String toString() {
String resultString = "I am a data array with " + length + " items.\r\n";
for (int i = 0; i < length; i++) {
resultString += data[i] + " ";
}
return resultString;
}
public String sequentialSearch(int paraKey) {
data[0].key = paraKey;
int i;
//由于数据[0].key=paraKey,所以我们不判断i>=0。
//这样运行时节省了大约1/2。
for (i = length - 1; data[i].key != paraKey; i--)
;
return data[i].content;
}
public static void sequentialSearchTest() {
int[] tempUnsortedKeys = { -1, 5, 3, 6, 10, 7, 1, 9 };
String[] tempContents = { "null", "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
System.out.println("Search result of 10 is: " + tempDataArray.sequentialSearch(10));
System.out.println("Search result of 5 is: " + tempDataArray.sequentialSearch(5));
System.out.println("Search result of 4 is: " + tempDataArray.sequentialSearch(4));
}
public String binarySearch(int paraKey) {
int tempLeft = 0;
int tempRight = length - 1;
int tempMiddle = (tempLeft + tempRight) / 2;
while (tempLeft <= tempRight) {
tempMiddle = (tempLeft + tempRight) / 2;
if (data[tempMiddle].key == paraKey) {
return data[tempMiddle].content;
} else if (data[tempMiddle].key <= paraKey) {
tempLeft = tempMiddle + 1;
} else {
tempRight = tempMiddle - 1;
}
}
//找不到
return "null";
}
public static void binarySearchTest() {
int[] tempSortedKeys = { 1, 3, 5, 6, 7, 9, 10 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempSortedKeys, tempContents);
System.out.println(tempDataArray);
System.out.println("Search result of 10 is: " + tempDataArray.binarySearch(10));
System.out.println("Search result of 5 is: " + tempDataArray.binarySearch(5));
System.out.println("Search result of 4 is: " + tempDataArray.binarySearch(4));
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
}
}
查找结果:
第 42 天: 哈希表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
1.使用 (最简单的) 除数取余法获得数据存放地址 (下标).
2.使用 (最简单的) 顺移位置法解决冲突.
3.搜索的时间复杂度仅与冲突概率相关, 间接地就与装填因子相关. 如果空间很多, 可以看出时间复杂度为O(1).
public DataArray(int[] paraKeyArray, String[] paraContentArray, int paraLength) {
// 初始化
length = paraLength;
data = new DataNode[length];
for (int i = 0; i < length; i++) {
data[i] = null;
}
// 填数据
int tempPosition;
for (int i = 0; i < paraKeyArray.length; i++) {
// 哈希
tempPosition = paraKeyArray[i] % paraLength;
// 找到一个空位置
while (data[tempPosition] != null) {
tempPosition = (tempPosition + 1) % paraLength;
System.out.println("Collision, move forward for key " + paraKeyArray[i]);
}
data[tempPosition] = new DataNode(paraKeyArray[i], paraContentArray[i]);
}
}
public String hashSearch(int paraKey) {
int tempPosition = paraKey % length;
while (data[tempPosition] != null) {
if (data[tempPosition].key == paraKey) {
return data[tempPosition].content;
}
System.out.println("Not this one for " + paraKey);
tempPosition = (tempPosition + 1) % length;
}
return "null";
}
public static void hashSearchTest() {
int[] tempUnsortedKeys = { 16, 33, 38, 69, 57, 95, 86 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents, 19);
System.out.println(tempDataArray);
System.out.println("Search result of 95 is: " + tempDataArray.hashSearch(95));
System.out.println("Search result of 38 is: " + tempDataArray.hashSearch(38));
System.out.println("Search result of 57 is: " + tempDataArray.hashSearch(57));
System.out.println("Search result of 4 is: " + tempDataArray.hashSearch(4));
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
}
哈希表的插入与查找结果:
第 43 天: 插入排序
插入排序,一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。
插入排序是一种最简单的排序方法,它的基本思想是将一个元素插入到已经排好序的有序表中,从而形成一个新的、元素数加1的有序表。
在其实现过程使用双层循环,外层循环对除了第一个元素之外的所有元素,内层循环对当前元素前面有序表进行待插入位置查找,并进行移动 。
代码:
public void insertionSort() {
DataNode tempNode;
int j;
for (int i = 2; i < length; i++) {
tempNode = data[i];
//找到插入的位置并移动后面的元素
for (j = i - 1; data[j].key > tempNode.key; j--) {
data[j + 1] = data[j];
}
//插入
data[j + 1] = tempNode;
System.out.println("Round " + (i - 1));
System.out.println(this);
}
}
public static void insertionSortTest() {
int[] tempUnsortedKeys = { -100, 5, 3, 6, 10, 7, 1, 9 };
String[] tempContents = { "null", "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.insertionSort();
System.out.println("Result\r\n" + tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
}
插入排序结果:
第 44 天: 希尔排序
希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至 1 时,整个文件恰被分成一组,算法便终止。
图解:
public void shellSort() {
DataNode tempNode;
int[] tempJumpArray = { 5, 3, 1 };
int tempJump;
int p;
for (int i = 0; i < tempJumpArray.length; i++) {
tempJump = tempJumpArray[i];
for (int j = 0; j < tempJump; j++) {
for (int k = j + tempJump; k < length; k += tempJump) {
tempNode = data[k];
// 找到插入位置,并移动元素
for (p = k - tempJump; p >= 0; p -= tempJump) {
if (data[p].key > tempNode.key) {
data[p + tempJump] = data[p];
} else {
break;
}
}
//插入
data[p + tempJump] = tempNode;
}
}
System.out.println("Round " + i);
System.out.println(this);
}
}
public static void shellSortTest() {
int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9, 12, 8, 4 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while", "throw", "until", "do" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.shellSort();
System.out.println("Result\r\n" + tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
System.out.println("\r\n-------shellSortTest-------");
shellSortTest();
}
希尔排序结果:
第 45 天: 冒泡排序
双重循环,只交换相邻位置,每次确定当前无序中的最大值,也就是每趟排序可以确定一个元素的最终位置,如果某一趟没有交换,表示已经排好序,结束循环。
代码:
其中tempNode需要初始化NULL,不然会报错。
public void bubbleSort() {
boolean tempSwapped;
DataNode tempNode = null;
for (int i = length - 1; i > 1; i--) {
tempSwapped = false;
for (int j = 0; j < i; j++) {
if (data[j].key > data[j + 1].key) {
//交换
tempNode = data[j + 1];
data[j + 1] = data[j];
data[j] = tempNode;
tempSwapped = true;
}
}
//如果本趟循环没有交换,则说明已经有序
if (!tempSwapped) {
System.out.println("Premature");
break;
}
System.out.println("Round " + (length - i));
System.out.println(this);
}
}
public static void bubbleSortTest() {
int[] tempUnsortedKeys = { 1, 3, 6, 10, 7, 5, 9 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.bubbleSort();
System.out.println("Result\r\n" + tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
System.out.println("\r\n-------shellSortTest-------");
shellSortTest();
System.out.println("\r\n-------bubbleSortTest-------");
bubbleSortTest();
}
冒泡排序结果:
第 46 天: 快速排序
快速排序,就是给基准数据找其正确索引位置的过程。
①先从队尾开始向前扫描且当low < high时,如果a[high] > tmp,则high–,但如果a[high] <tmp,则将high的值赋值给low,即arr[low] = a[high],同时要转换数组扫描的方式,即需要从队首开始向队尾进行扫描了。
②同理,当从队首开始向队尾进行扫描时,如果a[low] < tmp,则low++,但如果a[low] >tmp了,则就需要将low位置的值赋值给high位置,即arr[low] =arr[high],同时将数组扫描方式换为由队尾向队首进行扫描。
③不断重复①和②,知道low>=high时(其实是low=high),low或high的位置就是该基准数据在数组中的正确索引位置。
快速排序的平均时间复杂度为O(nlgn),当序列基本有序时时间复杂度最坏,为O(n2).
public void quickSortRecursive(int paraStart, int paraEnd) {
//快排结束
if (paraStart >= paraEnd) {
return;
}
int tempPivot = data[paraEnd].key;
DataNode tempNodeForSwap;
int tempLeft = paraStart;
int tempRight = paraEnd - 1;
//找到枢轴的位置,同时将较小的元素向左移动,将较大的元素向右移动
while (true) {
while ((data[tempLeft].key < tempPivot) && (tempLeft < tempRight)) {
tempLeft++;
}
while ((data[tempRight].key > tempPivot) && (tempLeft < tempRight)) {
tempRight--;
}
if (tempLeft < tempRight) {
//交换
System.out.println("Swapping " + tempLeft + " and " + tempRight);
tempNodeForSwap = data[tempLeft];
data[tempLeft] = data[tempRight];
data[tempRight] = tempNodeForSwap;
} else {
break;
}
}
//交换
if (data[tempLeft].key > tempPivot) {
tempNodeForSwap = data[paraEnd];
data[paraEnd] = data[tempLeft];
data[tempLeft] = tempNodeForSwap;
} else {
tempLeft++;
}
System.out.print("From " + paraStart + " to " + paraEnd + ": ");
System.out.println(this);
quickSortRecursive(paraStart, tempLeft - 1);
quickSortRecursive(tempLeft + 1, paraEnd);
}
public void quickSort() {
quickSortRecursive(0, length - 1);
}
public static void quickSortTest() {
int[] tempUnsortedKeys = { 1, 3, 12, 10, 5, 7, 9 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.quickSort();
System.out.println("Result\r\n" + tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
System.out.println("\r\n-------shellSortTest-------");
shellSortTest();
System.out.println("\r\n-------bubbleSortTest-------");
bubbleSortTest();
System.out.println("\r\n-------quickSortTest-------");
quickSortTest();
}
快排结果:
第 47 天: 选择排序
选择排序(Selection sort)是一种简单直观的排序算法。
它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法。
每趟排序可以确定一个元素的位置。
时间复杂度为O(n)
public void selectionSort() {
DataNode tempNode;
int tempIndexForSmallest;
for (int i = 0; i < length - 1; i++) {
//初始化
tempNode = data[i];
tempIndexForSmallest = i;
for (int j = i + 1; j < length; j++) {
if (data[j].key < tempNode.key) {
tempNode = data[j];
tempIndexForSmallest = j;
}
}
//更改当前元素
data[tempIndexForSmallest] = data[i];
data[i] = tempNode;
}
}
public static void selectionSortTest() {
int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.selectionSort();
System.out.println("Result\r\n" + tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
System.out.println("\r\n-------shellSortTest-------");
shellSortTest();
System.out.println("\r\n-------bubbleSortTest-------");
bubbleSortTest();
System.out.println("\r\n-------quickSortTest-------");
quickSortTest();
System.out.println("\r\n-------selectionSortTest-------");
selectionSortTest();
}
选择排序结果:
第 48 天: 堆排序
堆排序是利用堆(二叉树)这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
步骤一 构造初始堆。将给定无序序列构造成一个大顶堆(一般升序采用大顶堆,降序采用小顶堆)。
步骤二 将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素。如此反复进行交换、重建、交换。最后生成一个有序的堆。
public void heapSort() {
DataNode tempNode;
//建立初试堆
for (int i = length / 2 - 1; i >= 0; i--) {
adjustHeap(i, length);
}
System.out.println("The initial heap: " + this + "\r\n");
//交换和重建堆
for (int i = length - 1; i > 0; i--) {
tempNode = data[0];
data[0] = data[i];
data[i] = tempNode;
adjustHeap(0, i);
System.out.println("Round " + (length - i) + ": " + this);
}
}
public void adjustHeap(int paraStart, int paraLength) {
DataNode tempNode = data[paraStart];
int tempParent = paraStart;
int tempKey = data[paraStart].key;
for (int tempChild = paraStart * 2 + 1; tempChild < paraLength; tempChild = tempChild * 2 + 1) {
//右孩子更大
if (tempChild + 1 < paraLength) {
if (data[tempChild].key < data[tempChild + 1].key) {
tempChild++;
}
}
System.out.println("The parent position is " + tempParent + " and the child is " + tempChild);
if (tempKey < data[tempChild].key) {
//更大的孩子交换
data[tempParent] = data[tempChild];
System.out.println("Move " + data[tempChild].key + " to position " + tempParent);
tempParent = tempChild;
} else {
break;
}
}
data[tempParent] = tempNode;
System.out.println("Adjust " + paraStart + " to " + paraLength + ": " + this);
}
public static void heapSortTest() {
int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.heapSort();
System.out.println("Result\r\n" + tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
System.out.println("\r\n-------shellSortTest-------");
shellSortTest();
System.out.println("\r\n-------bubbleSortTest-------");
bubbleSortTest();
System.out.println("\r\n-------quickSortTest-------");
quickSortTest();
System.out.println("\r\n-------selectionSortTest-------");
selectionSortTest();
System.out.println("\r\n-------heapSortTest-------");
heapSortTest();
}
堆排序结果:
第 49 天: 归并排序
归并排序(Merge Sort)是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并排序进行 log n 轮循环,每轮O(n) 次拷贝,因此时间复杂度为 O(nlog n)。
public void mergeSort() {
int tempRow; // 现在的Row
int tempGroups; // 数组个数
int tempActualRow; // 只有0和1
int tempNextRow = 0;
int tempGroupNumber;
int tempFirstStart, tempSecondStart, tempSecondEnd;
int tempFirstIndex, tempSecondIndex;
int tempNumCopied;
for (int i = 0; i < length; i++) {
System.out.print(data[i]);
}
System.out.println();
DataNode[][] tempMatrix = new DataNode[2][length];
//赋值
for (int i = 0; i < length; i++) {
tempMatrix[0][i] = data[i];
}
//logn次循环
tempRow = -1;
for (int tempSize = 1; tempSize <= length; tempSize *= 2) {
// 重新利用
tempRow++;
System.out.println("Current row = " + tempRow);
tempActualRow = tempRow % 2;
tempNextRow = (tempRow + 1) % 2;
tempGroups = length / (tempSize * 2);
if (length % (tempSize * 2) != 0) {
tempGroups++;
}
System.out.println("tempSize = " + tempSize + ", numGroups = " + tempGroups);
for (tempGroupNumber = 0; tempGroupNumber < tempGroups; tempGroupNumber++) {
tempFirstStart = tempGroupNumber * tempSize * 2;
tempSecondStart = tempGroupNumber * tempSize * 2 + tempSize;
if (tempSecondStart > length - 1) {
//复制第一部分
for (int i = tempFirstStart; i < length; i++) {
tempMatrix[tempNextRow][i] = tempMatrix[tempActualRow][i];
}
continue;
}
tempSecondEnd = tempGroupNumber * tempSize * 2 + tempSize * 2 - 1;
if (tempSecondEnd > length - 1) {
tempSecondEnd = length - 1;
}
System.out
.println("Trying to merge [" + tempFirstStart + ", " + (tempSecondStart - 1)
+ "] with [" + tempSecondStart + ", " + tempSecondEnd + "]");
tempFirstIndex = tempFirstStart;
tempSecondIndex = tempSecondStart;
tempNumCopied = 0;
while ((tempFirstIndex <= tempSecondStart - 1)
&& (tempSecondIndex <= tempSecondEnd)) {
if (tempMatrix[tempActualRow][tempFirstIndex].key <= tempMatrix[tempActualRow][tempSecondIndex].key) {
tempMatrix[tempNextRow][tempFirstStart
+ tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex];
tempFirstIndex++;
System.out.println("copying " + tempMatrix[tempActualRow][tempFirstIndex]);
} else {
tempMatrix[tempNextRow][tempFirstStart
+ tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex];
System.out.println("copying " + tempMatrix[tempActualRow][tempSecondIndex]);
tempSecondIndex++;
}
tempNumCopied++;
}
while (tempFirstIndex <= tempSecondStart - 1) {
tempMatrix[tempNextRow][tempFirstStart
+ tempNumCopied] = tempMatrix[tempActualRow][tempFirstIndex];
tempFirstIndex++;
tempNumCopied++;
}
while (tempSecondIndex <= tempSecondEnd) {
tempMatrix[tempNextRow][tempFirstStart
+ tempNumCopied] = tempMatrix[tempActualRow][tempSecondIndex];
tempSecondIndex++;
tempNumCopied++;
}
}
System.out.println("Round " + tempRow);
for (int i = 0; i < length; i++) {
System.out.print(tempMatrix[tempNextRow][i] + " ");
}
System.out.println();
}
data = tempMatrix[tempNextRow];
}
public static void mergeSortTest() {
int[] tempUnsortedKeys = { 5, 3, 6, 10, 7, 1, 9 };
String[] tempContents = { "if", "then", "else", "switch", "case", "for", "while" };
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
tempDataArray.mergeSort();
System.out.println(tempDataArray);
}
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
binarySearchTest();
System.out.println("\r\n-------hashSearchTest-------");
hashSearchTest();
System.out.println("\r\n-------insertionSortTest-------");
insertionSortTest();
System.out.println("\r\n-------shellSortTest-------");
shellSortTest();
System.out.println("\r\n-------bubbleSortTest-------");
bubbleSortTest();
System.out.println("\r\n-------quickSortTest-------");
quickSortTest();
System.out.println("\r\n-------selectionSortTest-------");
selectionSortTest();
System.out.println("\r\n-------heapSortTest-------");
heapSortTest();
System.out.println("\r\n-------mergeSortTest-------");
mergeSortTest();
}
归并排序结果:
第 50 天: 小结
比较分析各种查找算法.
- 顺序查找
顺序查找,按照字面意思,就是按照排列顺序,依次将查找关键词key与元数据每一项进行对比,如果找到就结束。 适用所有数据,但是对于过大的数据,不太实用,时间复杂度较高 ,时间复杂度O(n),空间复杂度O(1)
2.折半查找
假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
适用范围数据有序,时间复杂度O(log n),空间复杂度O(1)
3.哈希表查找
根据键值方式(Key value)进行查找,通过散列函数,定位数据元素。首先需要建立hash表。时间复杂度在不冲突的情况下O(1),最极端情况为O(n),空间复杂度O(1)
设计一个自己的 Hash 函数和一个冲突解决机制.
根据哈希表长度,每次求余哈希表的长度,得到的值就作为存放位置,当遇到相同的,就依此顺移
比较分析各种排序算法并描述各种排序算法的特点和基本思想…
直接插入排序:
每次取一个记录插入到已经排好序的有序表中,得到一个新的有序表。在插入过程中为了防止下标出界,需要在r[0]处加入一个监视哨。该算法的时间复杂度为O(n2),双层嵌套循环;空间复杂度为O(1),因为只需要一个额外的空间存储监视哨。
希尔排序:
希尔排序是由直接插入排序发展而来,将待排序列分割成若干个子序列,并分别进行直接插入排序,(子序列是由相隔某个增量的记录组成的,而非分段),最后进行一次直接插入排序。注意:增量序列的值应该没有除1以外的公因子,且最后一个增量值必须为1.该算法的时间复杂度小于O(n2),与选取的增量值相关。
冒泡排序:
每一轮排序都从第一位开始将相邻的两位进行比较,如果t-1位比t位的值大,则将其交换顺序。每轮排序后,都会将未排序序列的最大数移到最后一位。当开始时序列即为从小到大有序序列,只需要一次就可以完成排序,时间复杂度为O(n); 当序列为逆序排列时,所需排序次数为n-1次,每次比较的次数为n-i次,时间复杂度为O(n2);算法的平均时间复杂度为O(n2)
快速排序:
第一趟快排将列表分为两部分,一部分的关键字均比另一部分关键字小,然后再分别对两部分进行排序。算法首先选定一点作为枢纽,然后分别设置两个指针low和high,high从尾部开始,找到小于枢纽的点,将其与枢纽交换;然后low从头部开始找到大于枢纽的点将其与枢纽交换。依次排序后以枢纽为中心分为两部分,且左边均比枢纽小,右边均比枢纽大。快速排序的平均时间复杂度为所有内部排序中最优的,但是在序列有序的情况下,其性能不能达到O(n)。空间复杂度为O(logn),因为每次快排包括递归过程中的枢纽值,都需要存储在一个栈中。
归并排序:
是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序进行 log n 轮循环,每轮O(n) 次拷贝,因此时间复杂度为 O(nlog n)。
堆排序:
堆排序是利用堆(二叉树)这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。