力扣排序算法


1.冒泡排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int temp;
        for(int i=0;i<nums.size()-1;i++)
        {
            bool flag = false; 
            for(int j=0;j<nums.size()-1-i;j++)
            {
                if(nums[j] > nums[j+1])
                {
                    temp = nums[j+1];
                    nums[j+1] = nums[j];
                    nums[j] = temp; 
                    flag = true;
                }
            }
            if(!flag) break;// 循环无交换,就结束
        }
        return nums;
    }
};

时间复杂度:n^2 稳定排序

2.选择排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        int minIndex;
        int n;
        n = nums.size();
        for(int i=0;i<n-1;i++)
        {
            minIndex = i;
            for(int j=i+1;j<n;j++)
            {
                if(nums[minIndex] > nums[j])
                {
                    minIndex = j;
                }
            }
            swap(nums[i],nums[minIndex]);
        }
        return nums;
    }
};

时间复杂度:n^2 不稳定排序

3.插入排序

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
       int key;
       int n=nums.size();
       // 默认第一个数字已经排序
       for(int i=1;i<n;i++)
       {
           key = nums[i];
           int j = i-1;
           // 前面默认排序号,i-1(j)就一定是最大的
           while(j>=0 && nums[j]>key)
           {
               nums[j+1] = nums[j];
               j--;
           }
        //    将key值插入
           nums[j+1] = key;
       }
       return nums;
    }
};

时间复杂度:n^2 稳定排序

4.希尔排序

希尔排序视频

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        //希尔排序(高级插入排序)
        int i, j, inc, n, key;
        n = nums.size();
        for (inc = n / 2; inc > 0; inc /= 2) {
            for (i = inc; i < n; i++) {
                j = i - inc;
                key = nums[i];
                while (j >= 0 && key < nums[j]) {
                    nums[j + inc] = nums[j];
                    j = j - inc;
                }
               nums[j + inc] = key;
            }
        }
        return nums;
    }
};

时间复杂度:O(n²)!~O(nlogn) 不稳定

5.快速排序

 void quickSort(vector<int>&nums,int startIndex,int endIndex)
    {
        if(startIndex >= endIndex)
            return;
        int left,right,priot;
        left = startIndex;
        right = endIndex;
        priot = nums[left];
        while(right>left)
        {
            //  右侧寻找小于左侧,用作交换的值
            while(nums[right]>=priot && right>left)
                right--;
            if(right>left)
            {
                nums[left] = nums[right];
            }
            while(nums[left]<=priot && right>left)
                left++;
            if(right>left)
            {
                nums[right] = nums[left];
            }
        }
        nums[left] = priot;
        quickSort(nums,startIndex,left-1);
        quickSort(nums,left+1,endIndex);
    }

时间复杂度nlogn,最坏n^2 空间复杂度logn

6.堆排序

学习视频
在这里插入图片描述

  1. 建大顶堆,递归的方法( O(n) )
  2. 堆顶就是最大值,依次将堆顶与堆末尾的数字交换,然后截去最大的那个数
  3. 继续堆排序
    时间复杂度:O( nlog(n) )
#include "../utils.h"

/**
 * 维护堆的性质
 * @param arr 存储堆的数组
 * @param len 数组长度
 * @param i 待维护节点的下标
 */
void heapify(int arr[], int len, int i)
{
    int largest = i;
    int lson = i * 2 + 1;
    int rson = i * 2 + 2;

    if (lson < len && arr[largest] < arr[lson])
        largest = lson;
    if (rson < len && arr[largest] < arr[rson])
        largest = rson;
    if (largest != i)
    {
        swap(&arr[largest], &arr[i]);
        heapify(arr, len, largest);
    }
}

// 堆排序入口
void heap_sort(int arr[], int len)
{
    int i;
    // 建堆
    for (i = len / 2 - 1; i >= 0; i--)
        heapify(arr, len, i);

    // 排序
    for (i = len - 1; i > 0; i--)
    {
        swap(&arr[i], &arr[0]);
        heapify(arr, i, 0);
    }
}

int main(int argc, char const *argv[])
{
    test(&heap_sort);
    return 0;
}

7.哈希表

原理:
在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_SIZE 16

typedef struct _ListNode{
	struct _ListNode *next;
	int key;
	void *data;
}ListNode; 

typedef ListNode *List;
typedef ListNode *Element;

typedef struct _HashTable{
	int TableSize;
	List *Thelists;
}HashTable;

// 哈希函数
int Hash(int key,int TableSize)
{
	return (key%TableSize);
} 

// 初始化HashTable 
HashTable *InitHash(int TableSize)
{
	int i=0;
	HashTable *hTable = NULL;
	if(TableSize<=0)
	{
		TableSize = DEFAULT_SIZE;
		}	
	hTable = (HashTable*)malloc(sizeof(HashTable));
	if(NULL == hTable)
	{
		printf("HashTable malloc error!\n");
		return NULL;
	}
	hTable->TableSize = TableSize;
	// 为Hash桶分配内存空间,其为一个指针数组
	hTable->Thelists = (List*)malloc(sizeof(List)*TableSize);
	if(NULL==hTable->Thelists)
	{
		printf("HashTable malloc error\n");
		free(hTable);
		return NULL;
		}	
	// 为Hash桶对应的指针数组初始化链表节点
	for(i=0;i<TableSize;i++)
	{
		hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
		if(NULL == hTable->Thelists[i])
		{
			printf("HashTable malloc error\n");
			free(hTable->Thelists);
			free(hTable);
			return NULL;
		}
		else
		{
			memset(hTable->Thelists[i],0,sizeof(ListNode));
		}
	 } 
	 return hTable;
} 
// 从哈希表中根据键值查找元素
Element Find(HashTable *HashTable ,int key)
{
	int i=0;
	List L= NULL;
	Element e = NULL;
	i = Hash(key,HashTable->TableSize);
	L = HashTable->Thelists[i];
	e = L->next;
	while(e != NULL && e->key != key)
	{
		e = e->next;
	}
	return e;
 } 
 
 void Insert(HashTable *HashTable,int key,void *value)
 {
 	Element e= NULL;
	Element tmp = NULL;
 	List L=NULL;
 	e = Find(HashTable,key);
 	if(NULL == e)
 	{
 		tmp = (Element)malloc(sizeof(ListNode));
 		if(NULL==tmp)
 		{
 			printf("mlloc error");
 			return ;
		 }
		 L = HashTable->Thelists[Hash(key,HashTable->TableSize)];
		 tmp->data = value;
		 tmp->key = key;
		 tmp->next = L->next;
		 L->next = tmp;
	 }
	 else{
	 	printf("the key already exist\n");
	 }
 }
 // 哈希表中提取元素 
 void *Retrieve(Element e)
 {
 	return e?e->data:NULL; 
 }
// 哈希表删除元素
void Delete(HashTable *HashTable,int key)
{
	Element e=NULL;
	Element last = NULL;
	List L= NULL;
	int i = Hash(key,HashTable->TableSize);
	L = HashTable->Thelists[i];
	last = L;
	e = L->next;
	while(e!=NULL && e->key!=key)
	{
		last = e;
		e = e->next;
	}
	// 如果键值对存在 
	if(e)
	{
		last->next=e->next;
		delete(e);
	}
 } 
int  main()
{
	char *elems[] = {"翠花","小芳","苍老师"};
	int i = 0;
	HashTable *HashTable;
	HashTable = InitHash(31);
	Insert(HashTable,1,elems[0]);
	Insert(HashTable,2,elems[1]);
	Insert(HashTable,3,elems[2]);
	Delete(HashTable,2);
	for(i=0;i<4;i++)
	{
		Element e = Find(HashTable,i);
		if(e){
			printf("%s\n",(const char*)Retrieve(e));
		}
		else
		{
			printf("Not found [key:%d]\n",i);
		}
	}
	system("pause");
	return 0;
}

8.八皇后问题

  1. 设置attack存储 0,1表示 是否可施放置,设置queen表示图哪里放置了皇后,solve存储字符结果
  2. 回溯法:第一行第一个放置皇后,将行 列 斜线设置为不可放置,去第二行放置皇后,直到到达最后一行,若是不能到达最后一行放置则回溯
#include <iostream>
#include <string>
#include <vector>
using namespace std;

void put_queen(int x,int y,vector<vector<int> >& attack)
{
//	printf("11\n");
	// 八个方向 
	static const int dx[] = {-1,1,0,0,-1,-1,1,1};
	static const int dy[] = {0,0,-1,1,-1,1,-1,1};
	// 皇后位置 
	attack[x][y] = 1;
	
	// 将皇后 (行 列 斜线)全部设置为1
	// 棋盘宽度 ,当i=0时,就是原位置,前面已经放置皇后了
	for(int i=1;i<attack.size();i++)
	{
		// 八个方向		
		for(int j=0;j<8;j++)
		{
			int nx = x + i*dx[j];
			int ny = y + i*dy[j];
			// 这里一定要注意是 < 不是 <= 
			if(nx>=0 && ny>=0 && nx<attack.size() && ny<attack.size())
			{
				attack[nx][ny] = 1;
			  }  
		}
	 } 
}

// 回溯法求n皇后问题
// k表示当前处理的行
// n表示n皇后问题
// queen存储皇后的位置
// attack标记皇后的攻击位置
// solve存储n皇后全部解法 
void backtrack(int k,int n,vector<string>& queen,
			vector<vector<int> >& attack,
			vector<vector<string> >& solve) 
{
//	printf("22\n");
	// 找到一组解 
	if(k==n)
	{
		solve.push_back(queen);
		return;
	}
	// 遍历 0~n-1列,k行所有尝试 
	for(int i=0;i<n;i++)
	{
		if(attack[k][i] == 0)
		{
			vector<vector<int> > temp = attack;
			queen[k][i] = 'Q';
			put_queen(k,i,attack);
			backtrack(k+1,n,queen,attack,solve);// 试探n+1行
			attack = temp; // 恢复为之前的状态 
			queen[k][i] = '.'; 
		}
	 } 
	
}

vector<vector<string> > solveNQueens(int n)
{
//	printf("33\n");
	vector<vector<string> > solve;
	vector<vector<int> > attack;
	vector<string> queen;
	
	for(int i=0;i<n;i++)
	{
		attack.push_back((vector<int>() ));
		for(int j=0;j<n;j++)
		{
			attack[i].push_back(0);
		}
		queen.push_back("");
		queen[i].append(n,'.');
	}
	backtrack(0,n,queen,attack,solve);
	return solve;
 } 

int main()
{
	vector<vector<string> > result;
	result = solveNQueens(8);
	printf("8皇后共有%d种解法:\n\n",result.size());
	for(int i=0;i<result.size();i++)
	{
		printf("解法%d:\n",i+1);
		for(int j=0;j<result[i].size();j++)
		{
			printf("%s\n",result[i][j].c_str());
		}
		printf("\n");
	}
	return 0;
 } 

9.满二叉树

满二叉树定义及描述(百度)
完全二叉树定义及描述(百度)

排序二叉树(二分搜索树) 查找效率:O(h)
在这里插入图片描述
二叉搜索树实现方法(中序遍历可以得到递增的排序序列)
在这里插入图片描述
二叉搜索树插入
二叉搜索树插入
二叉搜索树删除
第一‘二种情况
找左子树最大或右子树最小的代替(右子树中序遍历第一个)

在这里插入图片描述

遍历确定唯一二叉树

给定 先序+中序 or 后序+中序 可以唯一确定一颗二叉树

中序+后序确定二叉树:后序遍历的最后一个节点为root, 中序遍历中的root将二叉树划分为左、右子树,对于左右子树同样处理:递归
前序+中序确定二叉树:前序遍历的第一个节点为root, 中序遍历中的root将二叉树划分为左、右子树,对于左右子树同样处理:递归

而 先序+后序 不能
	  A
	 /
	B
前序遍历: AB, 后序遍历: BA
	A
	 \
	  B
前序遍历: AB, 后序遍历: BA

9.递归与非递归优缺点

递归的好处:代码相对非递归来说,更为简洁,并且思路清晰。
  递归的坏处:由于递归需要系统堆栈,所以消耗空间要比非递归大很多。并且,如果递归深度太深,可能会导致系统奔溃。

非递归的优点:效率高,执行时间只会因为循环的次数增加而增加,没什么额外开销,也不会占用额外空间。
   非递归的缺点:并不太容易理解,编写复杂问题时比较困难。

通俗地说,递归就是将问题层层细化、分解为多个小问题,然后一一解决。而非递归大多数情况下都编程者要去思考整个问题的解决办法,对编程者自身思维有很大挑战。

11.自上而下与自下而上算法

在这里插入图片描述

12.动态规划

动态规划:通过组合子问题的解来求解原问。不同于分治算法的互不相交,反复求解子问题,动态规划子问题可以重叠,且只求解一次,通常采用自底向上的方法。

  1. 确定dp[]含义
  2. 确定动态规划地推公式
  3. 确定初始化值
  4. 确定遍历顺序
  5. 打印数组

斐波那契数

class Solution {
public:
    int fib(int n) {
        if(n<2)
            return n;
        int MOD = 1000000007;
        int p = 0, q = 1,r;
        for(int i=2;i<=n;i++)
        {
            r = (p+q)%MOD;
            p = q;
            q = r;
        }
        return r;
    }
};

爬楼梯

class Solution {
public:
    int climbStairs(int n) {
        if(n<=2)
            return n;
        int p=1,q=2,r;
        for(int i=2;i<n;i++)
        {
            r = p+q;
            p = q;
            q = r;
        }
        return r;
    }
};

13.栈与队列

1.栈的基本应用

  1. 逆波兰式(后缀表达式)
  2. 栈在递归中的应用,
  3. 迷宫小车(寻路),
  4. 搜索引擎

2.队列的基本应用

  1. 树的层次遍历
  2. 图的广度优先遍历
  3. 队列在操作系统中的调度算法,如先来先服务。
  4. 搜索引擎,爬虫

二叉树先序遍历迭代法

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> res;
        if (root == nullptr) {
            return res;
        }

        stack<TreeNode*> stk;
        TreeNode* node = root;
        while (!stk.empty() || node != nullptr) {
            while (node != nullptr) {
                res.emplace_back(node->val);
                stk.emplace(node);
                node = node->left;
            }
            node = stk.top();
            stk.pop();
            node = node->right;
        }
        return res;
    }
};

用栈模拟队列

class MyQueue {

private:
    stack<int> inStack,outStack;
    void infoStack(){
        while(!inStack.empty())
        {
            outStack.push(inStack.top());
            inStack.pop();
        }
    }
public:
    MyQueue() {

    }
    
    void push(int x) {
        inStack.push(x);
    }
    
    int pop() {
        if(outStack.empty())
        {
            infoStack();
        }
        int x;
        x = outStack.top();
        outStack.pop();
        return x;
    }
    
    int peek() {
        if(outStack.empty())
        {
            infoStack();
        }
        int x = outStack.top();
        return x;
    }
    
    bool empty() {
        if(inStack.empty() && outStack.empty())
            return true;
        else
            return false;
    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

层序遍历(队列)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        // 定义一个二位数组
        vector<vector<int>> ret;
        // 当root为空指针时
        if(!root)
            return ret;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty())
        {
            int currentSize = q.size();
            vector<int> res;
            while(currentSize--)
            {
                auto node = q.front();
                q.pop();   
                res.push_back(node->val);
                if(node->left)
                    q.push(node->left);
                if(node->right)
                    q.push(node->right);
            }
            ret.push_back(res);
        }
        return ret;
    }
};

14.数据结构

数据结构(英语:data structure)是计算机中存储、组织数据的方式。
数据结构是一种具有一定逻辑关系,在计算机中应用某种存储结构,并且封装了相应操作的数据元素集合。它包含三方面的内容,逻辑关系、存储关系及操作。
不同种类的数据结构适合于不同种类的应用,而部分甚至专门用于特定的作业任务。例如,计算机网络依赖于路由表运作,B 树高度适用于数据库的封装。

15.广度优先遍历有深度优先遍历

深度优先遍历
主要思路是从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走。
应用:
小车遍历迷宫
二叉树的遍历
广度优先遍历
广度优先遍历,指的是从图的一个未遍历的节点出发,先遍历这个节点的相邻节点,再依次遍历每个相邻节点的相邻节点。
小车遍历迷宫
树的遍历
层序遍历
最短路径
![在这里插入图片描述](https://img-blog.csdnimg.cn/488ac822b37344829ac13f3eb32f052e.png

16.哈夫曼树

在这里插入图片描述
在这里插入图片描述
应用:哈夫曼编码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值