放一些基本的数据结构与算法的代码,方便复习,查漏补缺。
目录:
1. 直接插入排序
2. 折半直接插入排序
3. 快速排序
4. 归并排序
5. 冒泡排序
6. 堆排序
7. 希尔排序
8. 二叉树递归遍历
9. 二叉树非递归遍历
10. 二叉树层次遍历
11. kmp字符串搜索—待填
12. 头插法链表转置—待填
直接插入排序
假设前i个已经排好序,时间复杂度为O(n*n),稳定。
1 | void insert_sort(int *A,int size) |
折半直接插入排序
插入排序是将第i个数插入到,前i-1个有序数字里面,折半排序只是将在前i-1个有序树中查找的过程改成了二分法。由于数字移动次数没有改变,复杂度仍为O(N*N),稳定。
1 | void bs_insert_sort(int *A,int size) |
快速排序
平均复杂度为O(NlogN),最坏复杂度O(NN),即数据本来就是有序的,不稳定。
1 | int partition(int *A, int low,int high) |
归并排序
时间复杂度为O(N*logN),空间复杂度为O(N),稳定。
1 | void merge_array(int *A, int i, int j, int k,int *C) |
冒泡排序
冒泡是依次将最大的数冒泡到数组最后端,时间复杂度为O(N*N),稳定。最好加一个flag,如果某一趟遍历之后一个数据都没有交换,证明被遍历的部分数组本来就是有序的。
1 | void bubble_sort(int *A,int n) |
堆排序
堆排序相对比较复杂,堆是一个二叉树,首先对于数组A[n],i节点的子节点为2i+1和2i+2,i的父节点为(i-1)/2。调整堆时从最后一个叶子节点的父节点开始。
首先需要一个调整堆的函数fix(),这个函数的功能是调整A[i…n)为大根堆,他的假设是子树已经是大根堆,但调整之后可能会发生变化,所以要循环往下调整,如果调整之后子树仍然是大根堆就跳出循环。堆排序的第一步是建立一个大根堆,可以利用fix(),从最后一个叶子节点的父节点循环向堆顶调整;交换A[0]和A[n-1],用fix()调整A[0…n-1)(不包括n-1),调整完之后首尾交换…..
时间复杂度为O(N*logN),不稳定。
1 | //升序,调整A[i...n),不包括n |
希尔排序
希尔排序按步长进行直插排序,第一次步长为G,将A[0],A[G],A[2G]作为一组,A[1],A[1+G],A[1+2G]作为一组….,下一次迭代步长为G=G/2。步长为1是就是直接插入排序了。
时间复杂度为O(N1.25),不稳定。
1 | void shell_sort(int *A,int n) |
改进版即上面的for(i=0;i<gap;i++)和for(j=i;j<n;j+=gap)可以合并到一起。
1 | void shell_sort(int *A,int n) |
二叉树递归遍历
树的定义:
1 | struct BsTree |
树的建立请参见这里
先序遍历:
1 | void preorder_travel(BsTree *root) |
中序遍历:
1 | void inorder_travel(BsTree *root) |
后序遍历:
1 | void postorder_travel(BsTree *root) |
二叉树非递归遍历
非递归遍历实际就是用栈模拟递归调用过程。
前序遍历:先将根入栈,以队列不为空为循环条件,进入循环后开始出栈,出栈的同时按照先右后左的顺序将子节点入栈,比较无脑。
1 | vector<int> preorderTraversal(TreeNode* root) { |
中序遍历:中序遍历稍微要麻烦一点,需要设置一个是否出栈的flag,因为当一个节点出栈有两种情况,一个是没有左子树,还有一个是左子树已经被遍历过了。初始将flag设置为进栈,如果有左子树,左子树进栈。当该节点没有左子树时则直接出栈,且将右孩子入栈,若没有右孩子说明该节点的父节点左边已经遍历结束,此时flag设置为出栈,即父节点需要出栈。父节点出栈的同时父节点的右孩子入栈,flag设置为进栈。
1 |
|
后续遍历:后续遍历也要加一个标志,该标志记录最后一次出栈的元素。首先将根节点入栈,进入循环后,判断符不符合出栈的条件。出栈有两个条件:一个是该节点是一个叶子节点,另一个是该节点的孩子节点曾经被访问过,即标记位是否等于该节点的某一个孩子。由于入栈是将两个孩子按先右后左的顺序入栈,所以孩子一定在父节点之前出栈。两个条件满足其中一个便出栈,否则两个孩子均入栈。该题目在leetcode上标记为hard。
1 |
|
二叉树层次遍历
层序遍历利用队列,先将根加入队列,以队列不为空为循环条件,依次取队列的元素,出队列的同时将其左孩子和右孩子加入队列。如果需要按层次保存(打印),则每次循环的时候算一下队列的长度,一次性把队列内所有的元素(一层)都出队列。
1 |
|