c++库函数版数据结构

c++库函数版数据结构

基于stl库中vector的栈

栈的实现代码

栈属于序列的特例,故可直接基于向量或列表派生

template<typename T> class Stack public Vector<T>
{
    public:            //size()、empty()以及其它开放接口均可直接沿用
    void push(T const & e)//入栈
    {
        insert(size(),e;
    }
      T pop()//出栈
               {
                   return remove(size() - 1);
               }
       T & top()//返回栈顶元素
               {
                   return (*this)[size() - 1];
               }
};

栈的应用

1、逆序输出之进制转换

image-20210802141846313 image-20210802141855689
void convert(Stack<char> & S,_int64 n,int base)
{
    static char digit[] = 
{ '0','1','2','3','4','5','6','7','8','9','A','B','C','D,'E','F'};
    while(n>0){//由低到高,逐一计算出新进制下的各数位
	S.push(digit[n % base]);//余数(对应的数位)入栈
     n/=base;//n更新为其对base的除商
}
 }

2、递归嵌套之括号匹配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eRAsisHt-1630206361817)(https://raw.githubusercontent.com/huangguangchao/MAG/main/20210802151234.png)]

bool paren(const char exp[],int 1o,int hi)//exp[1o,hi]
{
	Stack<char>S//使用栈记录已发现但尚未匹配的左括号
    for(int i=1o;i< hi;i++)//逐一检查当前字符
    if('('==exp[i])
        s.push(exp[i]);//遇左括号:则进栈
    else if(!S.empty())
        S.pop();//遇有括号:若占非空,则弹出左括号
        else return false;//否则(遇右括号时钱已空),必不匹配
     return s.empty();//最终,栈空当且仅当匹配
}

为什么不直接使用计数器,遇到左括号加一遇到右括号减一这样?

因为如果出现中括号或方括号混搭的时候这样就行不通了,必须使用栈才能达到那个目的。

栈混洗总数:

image-20210802154159630

判断是否为栈混洗:

对于任何1<= i<j<k<=n,[…,[k],…,[i],…,[j],.…)(必非栈混洗)

3、延迟缓冲之中缀表达式求值

image-20210803143021635 image-20210803143045806

4、栈式计算之逆波兰表达式

​ 在由运算符(operator)和操作数(operand)组成的表达式中不使用活号(parenthesis-free),即可表示带优先级的运算关系

		遇到操作数就入栈,遇到单目运算符就弹出一个数,遇到双目运算符就弹出两个数,双目运算符对弹出的数字运算时先弹出的数字在运算符的右边,后弹出的数字在运算符左边进行运算。

image-20210803144957280

基于stl库中list函数的队列

只能在队尾插入(查询):enqueue()+rear()
只能在队头删除(查询):dequeue()+front()

template <typename T>class Queue:public List<T>
{  //由列表派生的队列模板类public:    //size()与empty()直接沿用
			void enqueue(T const&e)
			{
    			insertasLast(e);
			}//入队
   			 T dequeue()
             	{
       			 	return remove(first());
              	}//出队
    		T&front()
    			{
        			return first()->data;
    			}//队首
};//以列表首/末端为队列头/尾——颠倒过来呢?

基于stl库的树

​ 树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树称为结点的度(Degree)。度为0的结点称为叶结点(Leaf)或终端结点;度不为0的结点称为非终端结点或分支结点,除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。

image-20210803173156662

所有叶子深度中的最大者称作(子)树的高度

BinNode模板类

image-20210804150422697

BinNode接口实现

image-20210804150600016

BinTree模板类

image-20210804150843376

高度更新

image-20210804151546968

节点插入

image-20210804151946960

递归实现先中后根遍历(以先根为例)

image-20210804154023826

迭代实现

image-20210804154330593

迭代二:

image-20210804155916422 image-20210804155944120

基于stl库的图

template <typename(Tv),typename(Te)class Graph{//顶点类型、边类型
    private:
   void reset(){            //所有顶点、边的辅助信息复位
        for(int i = e;i < n;i++){      //顶点
		status(i) = UNDISCOVERED;
    	dTime(i) = fTime(i) = -1;      //时间标签   
   		 parent(i) = -1;
    	priority(i) = INT_MAX;
    	for(int j = e;j<n;j++)//边
     if(exists(i,j))
    status(i,j) = UNDETERMINED;
}
    }
public:/*...顶点操作、(边操作、图等法:|无论如何实现,接口必须统一..*/
}

顶点类

image-20210805154753369

边类

image-20210805154854146

临接矩阵

image-20210805155040661

顶点操作

Tv & vertex(int i){return V[i].data;}//数据
int inDegree(int i){return V[i].inDegree;}//入度
int outDegree(int i){return V[i].outDegree;}//出度
Vstatus & status(int i){return V[i].status;}//状态
int & dTime(int i){return V[i].dTime;}//时间标签dTime 
int & fTime(int i){return V[i].fTime;}//时间标签fTime 
int & parent(int i){return V[i].parent;}//在遍历树中的父亲
int & priority(int i){return V[i].priority;}//优先级数

对于任意顶点 i,如何枚举其所有的邻接顶点neighbor?

int nextNbr(int i,int j){//若已枚举至邻居j,则转向下一邻居
    while((-1 < j) && !exists(i,--j))//逆向顺序查找,0(n)
	return j;
}//改用邻接表可提高至0(1+outDegree(i))

首个邻居:
image-20210805160012691

如何插入一个顶点?

image-20210805160347764 如何删除一个顶点?

image-20210805160503317

边操作

判断边是否存在?

image-20210805160123083

边如何实现插入?

image-20210805160148096

边删除?

image-20210805160251290

遍历算法

广度优先遍历

image-20210805160724855

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G2ws9YZ8-1630206407975)(C:\Users\ASUS-PC\AppData\Roaming\Typora\typora-user-images\image-20210805170219879.png)]

广度优先算法

image-20210806123513964
图的具体实践(和上述方法不同)

#include<iostream>
#include<queue>
#define MAXVEX 10
#define INF 0
using namespace std;


class MGraph
{
public:
	void init()//初始化
	{
		for (int i = 0; i < MAXVEX; i++)
			for (int j = 0; j < MAXVEX; j++) 
				arc[i][j] = INF;
	}

	void InitVisited()
	{
		for (int i = 0; i < MAXVEX; i++)
			Visited[i] = 0;
	}

	void Creat()
	{
		int i, j, k, w;
		cout << "请输入定点数和边数:" << endl;
		cin >> vexnum >> edgenum;
		cout << "请输入顶点信息:" << endl;
		for (i = 0; i < vexnum; i++)
		{
			Vertex[i] = i;//存储序号
			cin >> Vername[i];//输入顶点名字

		}
		for (k = 0; k < edgenum; k++)
		{
			cout << "请输入边(vi,vj)的下标i,j和权w:";
			cin >> i >> j >> w;
			arc[i][j] = arc[j][i] = w;
		}
	}
		void Print()
		{
			cout << "临接矩阵:" << endl;
			for (int i = 0; i < vexnum; i++) {
				for (int j = 0; j < vexnum; j++)
					printf("%4d", arc[i][j]);
				cout << endl;
			}
		}

		int LocateVex(char ch)//返回顶点在图中的位置
		{
			int i;
			for (i = 0; i < vexnum; i++)
				if (ch == Vername[i])
				break;
				if (i == vexnum)
					return -1;
				else
					return i;			
		}

		void InsertVex(char ch)//增加某个顶点
		{
			Vertex[vexnum] = vexnum;
			Vername[vexnum] = ch;
			vexnum++;//顶点数自增

		}

		void InsertEdge(int i, int j, int w)//增加某条边
		{
			arc[i][j] = w;
			edgenum++;
		}

		void DeleteEdge(int i, int j)//删除某条边
		{
			arc[i][j] = INF;
			edgenum--;
		}
		
		void DeleteVex(char ch)//删除某个顶点
		{
			int i, j, k;
			for (i =0;i < vexnum; i++)//遍历寻找顶点位置
				if (ch == Vername[i])
					break;
			for (j = i; j < vexnum - 1; j++)//Vername数组循环左移
				Vername[j] = Vername[j + 1];//覆盖
			//arc数组循环左移和上移
			//上移
			for (j = i; j < vexnum - 1; j++)
				for (k = 0; k < vexnum; k++)
					arc[j][k] = arc[j + 1][k];
			for (k = 0; k < vexnum; k++)
				//左移
				for (j = 0; j < vexnum - 1; j++)
					for (k = i; k < vexnum - 1; k++)
						arc[j][k] = arc[j][k + 1];
			vexnum--;
		}



		//返回第一个邻接顶点
		char FirstADjVex(char ch)
		{
			int i,j;
			for (i = 0; i < vexnum; i++)
				if (ch == Vername[i])
					break;
			for (j = 0; j < vexnum; j++)
				if (arc[i][j] != INF)
					break;
			if (j == vexnum)
				return'\0';
			else
				return Vername[j];
		}

		//深度优先遍历
		void DFS(char ch)
		{
			int i, j, k;
			int l = LocateVex(ch);
			cout << Vername[l] << " ";//输出当前顶点
			Visited[l] = 1;//表示访问过该顶点
			for (i = 0; i < vexnum; i++)
				if (Visited[i] == 0 && arc[l][i] != INF)
					DFS(Vername[i]);
		}
		//广度优先遍历
		void BFS(char ch)
		{
			int i;
			queue<int>q;//定义队列
			int l = LocateVex(ch); //获取顶点位置
			cout << Vername[l] << " ";//输出当前顶点信息
			InitVisited();//Visited队列初始化
			q.push(l);//入队
			Visited[l] = 1;
			while (q.size())//一直循环直至队列为空
			{
				l = q.front();//获取队头信息
				q.pop();//出队
				for( i = 0;i<vexnum;i++)
					if (Visited[i] == 0 && arc[l][i] != INF)
					{
						cout << Vername[i] << " ";//访问顶点
						q.push(i);//入队
						Visited[i] = 1;//表示已访问
					//	cout << "i = " << i << endl;
						//cout << "Visited[i] = " << Visited[i]<<endl;
					}
				
				
			}
		}


private:
	int Vertex[MAXVEX];//结点序号
	char Vername[MAXVEX];//结点名字
	int arc[MAXVEX][MAXVEX];//邻接矩阵
	int vexnum;//顶点数
	int edgenum;//边数
	int Visited[MAXVEX];
};

int main()
{
	MGraph mygraph;
	mygraph.init();
	mygraph.Creat();
	mygraph.Print();
	mygraph.InitVisited();
	char ch;
	cout << "请输入要增加的顶点信息";
	cin >> ch;
	mygraph.InsertVex(ch);
	mygraph.Print();
	cout << "请输入要删除的顶点信息";
	cin >> ch;
	mygraph.DeleteVex(ch);
	mygraph.Print();
	cout<<"请输入要查找的顶点:";
	cin >> ch;
	ch = mygraph.FirstADjVex(ch);
	if (ch == '\0')
		cout << "该顶点不存在" << endl;
	else
		cout << "该顶点的第一个邻接顶点是" << ch;
	cout << "请输入起点顶点的信息";
	cin >> ch;
	cout << "深度优先遍历:" << endl;
	mygraph.DFS(ch);
	
	//广度优先遍历
	cout << "请输入起点顶点信息";
	cin >> ch;
	cout << "广度优先遍历"<<endl;
	mygraph.BFS(ch);

	cout << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hgchshs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值