1.常用的排序算法及其时间、空间复杂度
插入排序:对于一个数组来说,初始其有序数组元素个数为1,然后从第二个元素开始插入到有序数组中。对于每一次插入操作,从后往前遍历,若是当前元素大于要插入的元素,则继续前移一位,若是当前元素小于或等于要插入的元素,则将要插入的元素插入当前元素的后一位中。
希尔排序:先取一个小于n的整数a作为第一个增量,然后将所有距离为a的倍数的记录放在同一个组中。现在各组内进行直接插入排序;然后取第二个增量b<a重复上述分组和排序,知道所取的增量为1,即所有记录放在同一组中进行直接插入排序为止。
归并排序:采用分治法,对包含m个元素的待排序序列,将其看成m个长度为1的子序列,然后两两合并,得到n/2个长度为2或者1的有序子序列,然后继续两两归并,直到得到一个长度为m的有序序列。
冒泡排序:对于包含n个元素的数组,重复遍历数组,首先比较第一个与第二个元素,若为逆序则交换元素位置,然后比较第二个和第三个元素,重复上诉操作。
快速排序:首先设定一个分解值,通过该分解值将数组分成左右两部分。将大于或等于分解值的数据集中到数组右边,小于分界值的集中到数组左边。此时,左边部分中各元素均小于右边部分;然后又分别对左边和右边数据进行排序,分别选择一个分界值,将小于分界值的数放在左边,大于或等于的值放在右边。重复直至整个数组的排序完成。
选择排序:从待排序的数据元素中选取最小的一个元素,存放在序列的起始位置,然后从剩余元素中找最小值,以此类推。
堆排序:在堆的数据结构中,堆中的最大值总是位于根节点。将待排序的数据构造一个最大堆,然后将堆顶元素与待排序数组的最后一个元素交换位置,此时末尾元素就是最大值,然后将剩余元素重新构造成最大堆。
算法 时间复杂度 空间复杂度 稳定性
插入 n^2 1 稳定
希尔 nlogn 1 不稳定
归并 nlogn n 稳定
冒泡 n^2 1 稳定
快速 nlogn nlogn 不稳定
选择 n^2 1 不稳定
堆 nlogn 1 不稳定
2.手写快排代码
#include<iostream>
#include<vector>
using namespace std;
//首先找到一个参考值,将大于或等于参考值的数放在参考值后面;将小于参考值的数放在参考值前面
int on_quick_sort(vector<int> &nums,int left, int right){
//先从右向左移动,找到第一个小于k的值,将之保存在前面的空位中,此时该位置为空位;然后从左向右找到第一个大于等于k的值,将之保存在之前的空位中,此时该位置为空,直到左右指针相遇,此时相遇位置为空,则将参考值保存在空位置中,此时参考值左边均为小于参考值,右边均大于等于参考值
int k=nums[left];//将当前数组范围内的第一个数作为参考值取出来保存,此时该位置位空位
while(left<right){//因此需要判断左右指针还未相遇时,对值进行互换
while(left<right&&k<=nums[right]){//从右往左,直到找到第一个小于参考值的值
right--;
}
if(left<right){//将该值放入之前的空位置中,此时该位置为空位置
nums[left++]=nums[right];
}
while(left<right&&nums[left]<k){//然后从左往右,找到第一个大于等于参考值的值
left++;
}
if(left<right){//将该值放入之前的空位置中,此时该位置为空位置
nums[right--]=nums[left];
}
}
nums[left]=k;//左右指针相遇时,调整完成,将参考值放入最后的空位置中
return left;//返回此时参考值的位置
}
int quick_sort(vector<int> &nums,int left,int right){
if(left>=right){
return 1;
}
int middle=on_quick_sort(nums,left,right);
on_quick_sort(nums,left,middle-1);
on_quick_sort(nums,middle+1,right);;
}
int main(){
vector<int> p;
int a;
while(cin>>a){
p.push_back(a);
}
int n=p.size();
quick_sort(p,0,n-1);
for(int i=0;i<n;i++){
cout<<p[i]<' ';
}
return 0;
}
3.二叉树
3.1二叉树的逻辑结构: 每个节点最多两颗子树,子树有次序之分
//完全二叉树:除了第h层外,其他各层的结点数均达到最大个数。 若完全二叉树高度为h,则该二叉树有2^h-1个结点。
//满二叉树:除了最后一层无任何子结点以外,每一层上的所有结点都有两个子结点的二叉树
typedef struct BTNode{
int data;
BTNode* lChild;
BTNode* rChild;
}BTNode;
3.2二叉树的层次遍历
则层次遍历的结果为ABCDEF。利用队列先进先出的特性来表示。先将A入队,然后A出队,访问A,将A 的子结点BC读入队列,,然后B出队,访问B的子结点,C出队访问C的子结点。
void level(BTNode *bt)
{
if(bt!=NULL){
int front,rear;
BTNode *que[maxSize];
front=rear=0;
BTNode *p;
rear=(rear+1)%maxSize;
que[rear]=bt;
while(front!=rear)
{
front=(front+1)%maxSize;
p=que[front];
Visit(p);
if(p->lChild!=NULL)
{
rear=(rear+1)%maxSize;
que[rear]=p->lChild;
}
if(p->rChild!=NULL)
{
rear=(rear+1)%maxSize;
que[rear]=p->rChild;
}
}
}
}
***3.3***二叉树的前序遍历
a.递归
void preorder(BTNode *root){
if(root){
visit(root);
preorder(root->lChild);
preorder(root-rChild);
}
}
b.非递归
void preorder(BTNode *root){
if(root){
BTNode *s[maxSize];
int top=-1;
BTNode *p=NULL;
s[++top]=bt;
while(top!=-1){
p=s[top--];
visit(p);
if(p->rChild) s[++top]=p->rChild;
if(p->lChild) s[++top]=p->lChild;
}
}
}
3.4二叉树的中序遍历
a.递归
void inorder(BTNode *root){
if(root){
inorder(root->lChild);
visit(root);
inorder(root-rChild);
}
}
b.非递归
void inorder(BTNode *root){
if(root!=NULL){
BTNode *s[maxSize];int top=-1;
BTNode *p=NULL;
p=bt;
while(top!=-1||p!=NULL){
while(p!=NULL){
s[++top]=p;
p=p->lChild;
}
if(top!=-1){
p=s[top--];
visit(p);
p=p->rChild;
}
}
}
}
***3.5***二叉树的后序遍历
a.递归
void postorder(BTNode *root){
if(root){
postorder(root->lChild);
postorder(root-rChild);
visit(root);
}
}
b.非递归
void postorder(BTNode *root){
if(root){
BTNode *s1[maxSize],*s2[maxSize];
int top1=-1,top2=-1;
BTNode *p=NULL;
s1[++top]=bt;
while(top1!=-1){
p=s1[top--];
s2[++top2]=p;
if(p->lChild) s1[++top]=p->lChild;
if(p->rChild) s1[++top]=p->rChild;
}
while(top2!=-1){
p=s2[top2--];
visit(p);
}
}
}
4.树的高度和深度
高度是从下往上数,而深度是从上往下数。