算法汇总

算法设计应该满足特点:正确性、可使用性、可读性、健壮性、高效率低存储性

算法具有的特征:有限性、确定性、可行性、输入性、输出性

二叉树递归求和算法:

typedef struct BNode
{
int date;
struct BNode* lchild, * rchild;
}BTNode;

int Submt(BTNode* bt)
{
if (bt->lchild == NULL && bt->rchild == NULL)
return bt->date;
return Submt(bt->lchild) + Submt(bt->rchild) + bt->date;
}

递归求解数组最大值:

int fmax(int a[], int i)
{
if (i == 1)
return a[0];
return max(fmax(a, i - 1),a[i-1]);
}

递归删除单链表中所有数据:

void Destroy(ListNode* p)
{
if (p->next != NULL)
{
Destroy(p);
free(p);
}
}

二叉树递归查找x路径

bool Findxpath(BTNode *bt, int x, vector<int> temp, vector<int>& path)
{
if (bt == NULL)
return false;
temp.push_back(bt->date);
if (bt->date == x)
{
path = temp;
return true;
}
bool find = Findxpath(bt->lchild, x, temp, path);
if (find)
return true;
Findxpath(bt->rchild, x, temp, path);
}

递归输出各个位数的数字

void Find(int n)
{
if (n != 0)
{
Find(n / 10);
printf("%d", n % 10);
}
}

选择排序算法

void SelectSort(int a[], int n, int i)
{
int j,k;
if (i == n - 1)
return;
k = i;
for (j = i + 1; j < n; j++)
{
if (a[k] > a[j])
k = j;
}
if (k != i)
swap(a[i], a[k]);
SelectSort(a, n, i + 1);
}

分治法的时间复杂度

image-20210630100005664

快速排序用分治法实现:

int Partitionx(int a[], int s, int t)
{
   int i = s , j = t;
   int tmp = a[s]; //用序列的第1个记录作为基准
   while (i != j) //从序列两端交替向中间扫描,直至i=j为止    
  {
       while (j > i && a[j] >= tmp)
           j--;   //从右向左扫描,找第1个关键字小于tmp的a[j]
       a[i] = a[j]; //将a[j]前移到a[i]的位置
       while (i < j && a[i] <= tmp)
           i++;   //从左向右扫描,找第1个关键字大于tmp的a[i]
       a[j] = a[i]; //将a[i]后移到a[j]的位置
  }
   a[i] = tmp;
   return i;

}

void QuickSort(int a[], int l, int r)
{
   if (r <= l) return;
   int i = Partitionx(a, l, r);
   QuickSort(a, l, i - 1);
   QuickSort(a, i + 1, r);
}

自顶向下的二路归并排序算法

void Merge(int a[],int low,int mid,int high)
//a[low..mid]和a[mid+1..high]→a[low..high]
{
int* tmpa;
int i = low,j = mid + 1,k = 0;
tmpa = (int*)malloc((high - low + 1) * sizeof(int));
while (i <= mid && j <= high)
if (a[i] <= a[j]) //将第1子表中的元素放入tmpa中
{
tmpa[k] = a[i];  i++; k++;
}
else //将第2子表中的元素放入tmpa中
{
tmpa[k] = a[j]; j++; k++;
}
while (i <= mid) //将第1子表余下部分复制到tmpa
{
tmpa[k] = a[i]; i++; k++;
}
while (j <= high) //将第2子表余下部分复制到tmpa
{
tmpa[k] = a[j]; j++; k++;
}
for (k = 0,i = low; i <= high; k++,i++)  //将tmpa复制回a中
a[i] = tmpa[k];
free(tmpa); //释放tmpa所占内存空间
}

void MergePass(int a[],int length,int n)
//一趟二路归并排序
{
int i;
for (i = 0; i + 2 * length - 1 < n; i = i + 2 * length)   //归并length长的两相邻子表
Merge(a,i,i + length - 1,i + 2 * length - 1);
if (i + length - 1 < n)     //余下两个子表,后者长度小于length
Merge(a,i,i + length - 1,n - 1); //归并这两个子表
}

void sort(int a[],int n) //二路归并算法
{
int length;
for (length = 1; length < n; length = 2 * length)
MergePass(a,length,n);
}

折半查找(logn)

int BinSearch(int a[],int low,int high,int k)
{
    int mid;
    if (low <= high)		//当前区间存在元素时
    {
        mid = (low + high) / 2;	//求查找区间的中间位置
        if (a[mid] == k)		//找到后返回其物理下标mid
            return mid;
        if (a[mid] > k)		//当a[mid]>k时
            return BinSearch(a,low,mid - 1,k);
        else			//当a[mid]<k时
            return BinSearch(a,mid + 1,high,k);
    }
    else return -1;		//若当前查找区间没有元素时返回-1
}

查找最大和次大元素(n)

void solve(int a[],int low,int high,int &max1,int &max2)
{
    if (low == high)
    {
        max1 = a[low]; max2 = max1;
    }
    else if (low == high - 1)
    {
        max1 = max(a[low], a[high]);
        max2 = min(a[low], a[high]);
    }
    else
    {
        int mid = (low + high) / 2;
        int lmax1, lmax2;
        solve(a, low, mid, lmax1, lmax2);
        int rmax1, rmax2;
        solve(a, mid + 1, high, rmax1, rmax2);
        if (lmax1 > rmax1)
        {
            max1 = lmax1;
            max2 = max(lmax2, rmax1);
        }
        else
        {
            max1 = rmax1;
            max2 = max(lmax1, rmax2);	//lmax1,rmax2中求次大元素
        }
    }
}

寻找两个等长有序序列的中位数(logn)

int midnum(int a[],int s1,int t1,int b[],int s2,int t2)
{  //求两个有序序列a[s1..t1]和b[s2..t2]的中位数
  int m1,m2;
  if (s1==t1 && s2==t2)     //两序列只有一个元素时返回较小者
    return a[s1]<b[s2]?a[s1]:b[s2];
  else
  {  m1=(s1+t1)/2;		//求a的中位数
     m2=(s2+t2)/2;		//求b的中位数
     if (a[m1]==b[m2])	//两中位数相等时返回该中位数
      return a[m1];
     if (a[m1]<b[m2])	//当a[m1]<b[m2]时
     {   postpart(s1,t1);	//a取后半部分
        prepart(s2,t2);	//b取前半部分
       return midnum(a,s1,t1,b,s2,t2);
     }
      else			//当a[m1]>b[m2]时
      {  prepart(s1,t1);	//a取前半部分
        postpart(s2,t2);	//b取后半部分
        return midnum(a,s1,t1,b,s2,t2);
     }
  }
}

棋盘覆盖问题

void ChessBoard(int tr, int tc, int dr, int dc, int size)
{
    if (size == 1) return;
    int t = tile++;     //取出L,牌号为t
    int s = size / 2;   //分解棋盘
    if (dr < tr + s && dc < tc + s) //控制象限,大小于号控制
        ChessBoard(tr, tc, dr, dc, s);
    else
    {
        board[tr + s - 1][tr + s - 1] = t;  //控制棋盘,左上
        //board[tr+s][tr+s-1],右上
        //board[tr+s-1][tr+s],左下
        //board[tr+s][tr+s],右下
        ChessBoard(tr, tc, tr + s - 1, tc + s - 1, s);
    }
}

image-20210701144802771

0-1背包问题正好等于重量

void dfs(int i, int tw, int tv, int rw, int op[])   //rw为剩余可装重量
{
    int j;
    if (i > n)		//一个叶子结点找到
    {
        if (tw = W && tv > maxv)    //找到一个满足条件的更优解,保存
        {
            maxv = tv;
            for (j = 1; j <= n; j++)	//复制最优解
            {
                x[j] == op[j];
            }
        }
    }
    else 		//尚未找完所有物品
    {
        if (tw + w[i] <= W)    //左孩子结点剪枝 
        {
            op[i] = 1;			//选取第i个物品
            dfs(i + 1, tw + w[i], tv + v[i], rw - w[i], op);
        }
        if (tw + rw - w[i] >= W)
        {
            op[i] = 0;		//不选取第i个物品,回溯
            dfs(i + 1, tw, tv, rw - w[i], op);
        }
    }
}

求解最短路径

#define MAXN 51
#define INF 0x3f3f3f3f
int n;	//个数
int a[MAXN][MAXN];	//矩阵
int v;	//源点
int dist[MAXN];	//到顶点i的最短路径
int prevx[MAXN];	//前一个顶点

struct Node
{
	int vno;	//编号
	int length;	//长度
};

void bfs(int v)
{
	Node e, e1;
	queue<Node> pqu;
	e.vno = v;
	e.length = 0;
	pqu.push(e);
	dist[v] = 0;
	while (!pqu.empty())
	{
		e = pqu.front();
		e = pqu.pop();
		for (int j = 0; j < n; j++)
		{
			if (a[e.vno][j] < INF && e.length + a[e.vno][j] <= dist[j])	//剪枝
			{
				dist[j] = e.length + a[e.vno][j];
				prevx[j] = e.vno;
				e1.vno = j;
				e1.length = dist[j];
				pqu.push(e1);
			}
		}
	}
}

贪心算法性质:

1、贪心选择性质

2、最优子结构特征

 

算法设计条件:正确性、可使用性、可读性、健壮性、高效率低储存

算法的5个特征:有限性、确定性、可行性、输入性、输出性

 

posted @ 2021-07-06 10:01  S灬J  阅读(376)  评论(1编辑  收藏  举报