数据结构 - 前情提要

//自溜用

排序

插入排序
遍历 i , i 与前面的比较交换,直到遇到比 i 小的数

for(int i = 1;i < n;i++)
{
	int j = i - 1;
	int temp = A[i];
	while(j >= 0 && A[j] > temp)
	{
		A[j+1] = A[j];
		j--;
	}
	A[j+1] = temp;
}

冒泡排序
两两交换

for(int i = 1;i < n;i++)
	{
		for(int j = 0;j < n - i;j++)
		{
			if(A[j] > A[j+1])
				swap(A[j],A[j+1]);
		}
	}

选择排序
遍历 i ,找到后边比 i 小的Swap,不稳定

归并排序
MergeSort()递归,不断分割成局部数组
merge,通过n1,n2对两个局部数组取值,再整合成一个数组

void merge(int A[],int left,int mid,int right)
{
	int n1 = mid - left;
	int n2 = right - mid;
	for(int i = 0;i < n1;i++)	L[i] = A[left + i];
	for(int i = 0;i < n2;i++)	R[i] = A[mid + i];
	L[n1] = BIGNUM;
	R[n2] = BIGNUM;
	int i = 0,j = 0;
	for(int k = left;k < right;k++)
	{
		if(L[i] < R[j])
		{
			A[k] = L[i++];
		}
		else
		{
			A[k] = R[j++];
		}
	}
}
void MergeSort(int A[],int left,int right)
{
	if(left + 1 < right)
	{
		int mid = (left + right) / 2;
		MergeSort(A,left,mid);
		MergeSort(A,mid,right);
		merge(A,left,mid,right);
	}
}

快排
不断分割

//以中为基准的快排
void qsort(int left,int right)
{
    int i = left,j = right,mid = a[(i + j) / 2];
    while(i <= j)
    {
        while(a[i] < mid)   i++;
        while(a[j] > mid)   j--;
        if(i <= j)
        {
            swap(i++,j--);
        }
    }
    if(left < j)    qsort(left,j);
    if(right > i)   qsort(i,right);
}
//以最右为基准的快排
vector<int> part(vector<int>& v, int left,int right)
{
	//随机把最后的数和前面的交换,随机基准数,降低数据对算法的影响
    swap(v[right], v[rand() % (right - left + 1) + left]);
    int less = left, more = right - 1,cur = left;
    int x = v[right];
    for (; cur <= more; cur++)
    {
        if (x == v[cur])
            continue;
        else if (x > v[cur])
        {
            swap(v[less++], v[cur]);
        }
        else
        {
            swap(v[more--], v[cur--]);
        }
    }
    swap(v[right], v[more+1]);
    return vector<int>{ less,more };
}
void quicksort(vector<int>& v,int left,int right)
    {
        if (left < right)
        {
            vector<int> temp = part(v,left, right);
            quicksort(v,left, temp[0]-1);
            quicksort(v,temp[1] + 1, right);
        }
    }

普通树
树的结构: 左子右兄
递归设置 深度
在这里插入图片描述

二叉树
遍历方式 : 前中后

搜索二叉树
插入节点

Node *x ,*y ,*z;
	x = root;	//从root开始找
	y = NIL;	//储存上一个节点
	z = new Node(k,NIL,NIL);
	//NIL 为 nullptr
	
	//找到 z 该连接的 parent
	while(x != NIL)
	{
		y = x;
		if(z->key < x->key)
			x = x->left;
		else
			x = x->right;
	}
	z->parent = y;
	//连接 z 与 在 z 的parent
	if(y == NIL)
	{
		root = z;
	} 
	else
	{
		if(z->key < y->key)
			y->left = z;
		else	y->right = z;
	} 

删除节点
在这里插入图片描述

Node * z = nfind(num);
	if(z == nullptr)
	{
		cout << "未找到该节点" << endl;
		return;
	}
//进行节点的删除
Node * zp = z->parent;
//无子节点 
	if(z->left == nullptr && z->right == nullptr)
	{
		if(zp != nullptr)
		{
			if(z->parent->left == z)
				z->parent->left = nullptr;
			else
				z->parent->right = nullptr;
		}
		else
		{
			root = nullptr;
		}
		delete z;
		cout << "delete node" << endl;
		return;
	} 
//单个子节点
	if(z->left == nullptr && z->right != nullptr)
	{
		z->right->parent = z->parent;
		if(zp != nullptr)
		{
			if(z->parent->left == z)
				z->parent->left = z->right;
			else
				z->parent->right = z->right;
		}
		else
		{
			root = z->right;
			z->right->parent = nullptr;
		}
		delete z;
		cout << "delete node" << endl;
		return;
	}
	else if(z->left != nullptr && z->right == nullptr)
	{
		z->left->parent = z->parent;
		if(zp != nullptr)
		{
			if(z->parent->left == z)
			z->parent->left = z->left;
			else
			z->parent->right = z->left;
		}
		else
		{
			root = z->left;
			z->left->parent = nullptr;
		}
		delete z;
		cout << "delete node" << endl;
		return;
	}
//双节点 
	if(zp == nullptr)
	{
		root = z->right;
		z->right->parent = nullptr;
		
	}
	else
	{
		if(zp->left == z)
		{
			zp->left = z->right;
			z->right->parent = zp;
		}
		else
		{
			zp->right = z->right;
			z->right->parent = zp;
		}
	}
Node* min = getmin(z->right);
	min->left = z->left;
	z->left->parent = min->left;
	delete z;
	cout << "delete node" << endl;

线索二叉树
把叶子节点的空闲指针 用来 存储前驱后续

哈夫曼树 | 最优二叉树
一个队列 装 不同的 权值
取出最小的两个,合并为一个新的权值,放到队尾
哈夫曼算法:https://blog.csdn.net/u012011079/article/details/117449109
哈夫曼编码 通过哈夫曼算法可以实现 编码 与 解码
编码:通过栈装01,叶子节点向上进行编码

int cur,father;
stack<char> s;
	for(int i = 1;i <= n;i++)
	{
	string temp = "";
		cur = i;
		father = T[cur].parent;
		while(father != 0)
		{
		 	if(cur == T[father].L)
		 		s.push('0');
		 	else	s.push('1');
		 	cur = father;
		 	father = T[father].parent;
		}
		while(!s.empty())
		{
			temp += s.top();
			s.pop();
		}
		T[i].name = temp;
	}

解码,一个循环遍历所有01,if 判断是否叶子节点


用 树 的知识去管理 数组
i / 2 , i * 2 , i * 2 + 1

堆的重点:最大/小堆的生成

void maxHepify(int i)
{
int n;
int l = 2*i;
int r = 2*i+1;
	
	if(l <= H && A[l] > A[i])
		n = l;
	else	n = i;
	if(r <= H && A[r] > A[n])
		n = r;
	
	if(n != i)
	{
		swap(A[n],A[i]);
		maxHepify(n);
	}
}
void Run()
{
	for(int i = H/2;i >=1;i--)
	{
		maxHepify(i);
	}
}

某一元素插入进堆中

//key为插入的值
	H++;
	A[H] = key;
	int i = H;
	if(A[Parent(i)] > key)
	{
		return;
	}
	else
	{
		while(i > 1 && A[Parent(i)] < A[i])
		{
			swap(A[i],A[Parent(i)]);
			i = Parent(i);
		}
	}

去除最大堆最大的元素

A[1] = A[H];
H--;
maxHepify(1);

堆排序:在生成好堆后,不断将根节点取出

深搜DFS:逮住一条线往下搜
一个for遍历所有节点,进入DFS函数
DFS函数:对传进来的 节点 ,遍历与该节点连接的节点(未被搜过的)

广搜BFS:把周围的全搜了,再向外扩张
设置一个队列,将初始节点放进去
一个while(!queue.empty()),出队列,遍历出队列的节内未被搜过的节点,加入队列

加权图

最小生成树
prim算法:弄一个关于所有节点的 度的数组 ,进行一个循环:找出 度数组 中最小的度的点(未访问结束),遍历 该点
的度,并把 度数组 中的值更新,结束这个点(已访问)

while(true)
	{
		min = INF;
		u = -1;
		for(int i = 0;i < n;i++)	//找出未被访问的最小路径的点
		{
			if(color[i] != BLACK && d[i] < min)
			{
				u = i;
				min = d[i];
			}
		}
		if(u == -1)	break;	//循环退出条件
		
		color[u] = BLACK;
		
		for(int i = 0;i < n;i++)
		{
			if(color[i] != BLACK && INF != M[i][u])
			{
				if(d[i] > M[i][u])
				{
					d[i] = M[i][u];
					p[i] = u;
					color[i] = GRAY;
				}
			}
		}
	}

Kruskal算法:并查集。将边的权值排序,然后进行一个n-1次的循环,从权值中选最小的那条,用并查集判断是否可行,并查集的根不同,就进行下一次循环,相同就抛弃该边,遍历下一条边

while(num < n-1)	//n - 1 次外循环 
	{
		if(merge(e[index].u,e[index].v))
		{
			num++;
			sum += e[index].w;
		}
		index++;
	}

并查集

int find(int x)
{
	return x == fa[x] ? x : (fa[x] = find(fa[x]));
}

bool merge(int x,int y)
{
	x = find(x);
	y = find(y);
	if(x == y)
		return false;
	fa[y] = x;
	return true;
	
}

最短路径问题
Dijkstra算法:一个数组记录 V1 到其他顶点的 路径,先初始化,选出路径最小的节点,给予该节点一个“确定”,遍历该节点的出度,更新 V1数组,例如比较:V1-V3 : V1-V2-V3,进行循环,不断确定新的顶点

while(1)
	{
		u = -1;
		minv = INF;
		//取出目前出度最小的点(未被访问) 
		for(int i = 1;i <= n;i++)
		{
			if(Color[i] != BLACK && D[i] < minv)
			{
				minv = D[i];
				u = i;
			}
		}
		
		if(u == -1)	break;	//循环跳出条件
		
		//遍历所有的点 
		for(int i = 1;i <= n;i++)
		{
			if(Color[i] != BLACK && D[i] > D[u] + Graph[u][i])
			{
				D[i] = D[u] + Graph[u][i];
				P[i] = u;
			} 
		} 	
	}

SPFA:进行n-1次循环,每次循环对所有的边进行“松弛”

//u是起点数组,v在终点数组,w是权值
	for(int i = 1;i <= n-1;i++)	//循环节点数-1次 
	{
		for(int j = 1;j <= m;j++)	//遍历所有的边
		{
			if(D[v[i]] > D[u[i]] + w[i])
				D[v[i]] = D[u[i]] + w[i];
		} 
	} 

SPFA用队列的形式,val是 i 到 j 的权值

while(!q.empty())
	{
		temp = q.front();
		q.pop();
		exist[temp] = false;
		//遍历节点 temp 的所有连接点 
		for(int i = 0;i < g[temp].size();i++)
		{
			if(D[g[temp][i]] > D[temp] + val[temp][i])
			{
				D[g[temp][i]] = D[temp] + val[temp][i];
				if(!exist[g[temp][i]])
				{
					q.push(g[temp][i]);
					exist[g[temp][i]] = true;
				}
			}
		}
	}

Floyd算法:将一个二维数组 改进 为一个最短路径数组

//遍历所有节点,将二维数组g改造为最短路径数组 
	for(int k = 1;k <= n;k++)
		for(int j = 1;j <= n;j++)
			for(int i = 1;i <= n;i++)
				if(g[i][j] > g[i][k] + g[k][j])
					g[i][j] = g[i][k] + g[k][j];
					//k一定要在最外层 

拓扑排序
第一步:将所有入度为0的点放入栈中

//c[i]记录i节点出度的个数,r[i]记录i节点的入度
while(!s.empty())
	{
		temp = s.top();
		s.pop();
		for(int i = 1;i <= c[temp];i++)
		{
			r[g[temp][i]]--;
			if(r[g[temp][i]] == 0)
				s.push(g[temp][i]);
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值