数据结构 算法题练习第一期◇链表一元多项式◇括号的匹配

2021.12.13

学习了两个算法题,分别是链表一元多项式和括号的匹配,接下来分别解析两道题。

一,链表一元多项式

题目如下:

自定义一元多项式中的“项”结构,自定义一元多项式的链表结构。
设计函数Add(……),用于实现两个多项式的加法运算。
编写main()函数,分别读入两个多项式的数据,创建两个多项式链表。利用Add等函数,实现两个多项式的加法运算,并输出“多项式之和”的数据。要求按照多项式的幂的降序输出。

测试案例:
输入:

3
1 2
2 9
3 8
4
-3 8
5 2
3 10
9 0

输出:

3 10
2 9
6 2
9 0

解释:

第一个多项式是 2x^9+3x^8+x^2
第二个多项式是 3x^10-3x^8+5x^2+9
多项式之和是 3x^10+2x^9+6x^2+9

接下来先进行我的解题思路分享

先把链表构建好(因为我是在学习中,所以我不使用库,而是手搓了链表),链表中需要有指数,系数和next,同时我们也把重载放在了这个结构体Poly中

struct Poly
{
	int coef;
	int index;
	Poly *next;//多了个next域;
	friend ostream & operator<<(ostream &out, Poly &p)
	{
		return out<<p.coef<<" "<<p.index<<endl;
	}
};

因为我使用的是c++,我将会使用面向对象的方式来写函数部分

class PolyList
{
	Poly *Head;
public:
	PolyList(){}
	// 按照指数降序插入*newp
	void Insert(Poly *newp){}
	~PolyList(){}
	void RemoveHead(){}
	void Add(PolyList &L){}
	void Output(){}
};

在构造函数中我们将把数据放链表中,哦,别忘了头指针的初始化也是在构造函数中完成的。

PolyList()
	{
		Head=NULL;
		
		int n; cin>>n;
		for(int i=0; i<n; i++)
		{
			Poly *newp =new Poly;	
			cin>>newp->coef>>newp->index;
			Insert(newp); // 按照指数降序插入*newp;
		}
	}

 

先把newp和p连起来,再把head和newp连接起来 ,newp是一直在更新的,从Insert()外面传进来的值

再把head赋值给p


		Poly *prev=NULL, *p=Head;
		for(; p!=NULL; prev=p,p=p->next)
//循环的部分我写在下面

然后我们来说循环的意义,这就是个来进行newp和p大小比较的,如果交换了我们会用到prev来帮忙辅助进行数值交换

if(p->index <= newp->index)
				break;

此处,p->index是2,newp->index是9,所以直接break

那么我们聊下如果newp的指数比p小呢,那就直接把p链到prev,因为p的next是空的,所以把p这一节删了,至于怎么删,后面说。这一页我一开始理解错了

 在p之后插入newp,在prev后插入newp,是这个代码的核心

else
		{
			// 在*p之前插入*newp  在*prev之后插入*newp
			newp->next=p; 
			if(prev==NULL)
				Head      =newp;
			else
				prev->next=newp;
		}

newp完全给了head那这个newp的任务也就完成啦!这是我们第一次循环

小提一嘴,不想看的朋友这段可以直接跳过去3,但这一段在后面会用到

如果是9 2而非2 9,那我们就要动用prev,来进行排序交换了,最后会把prev链上newp

 

 

哦,第一次循环我就不提了,因为prev和p都是空,直接把newp给head基本就ok了

第三次循环,之前进行过的交换我就不提了,只提新的东西了

newp这次传进来的值是3 8

会初始化prev,并且把之前排好的,head完全给p,要知道,我们之前已经把head给填了2 9->1 2了

然后我们进行比较,会发现,我们需要把9和8进行交换,所以不break,进行一个prev=p,p=p->next,前一个prev=p,是动用prev先保存下来p的东西,这时候你观察地址会发现,prev和p地址是一样的了。然后p=p->next是我们之前埋下的一个,说好后面要用的,其实是p让next链的下面一个数据把自己覆盖了,就完成了消灭。

只要把newp接上p,就能看到3 8接上1 2了,那后面一定是2 9接上3 8接上1 2对吧

ok,因为这里prev不是空了,我们就可以用

if(prev==NULL)
				Head      =newp;
			else
				prev->next=newp;

的else段了,第二次循环用的是if,prev是最大的2 9,接上newp就是2 9接上3 8接上1 2啦!

一个疑问

这里prev不再给head好吗?

等会,你去调试下看看,这里prev怎么已经把值给head了!!!???

ok,这就是我们最后一个部分了,最终回

 先回答上面的问题,因为prev的next和head的next地址一样!所以 prev的next变,head的next也就变了

ok,那么这三次循环做完,其实也就差不多了,我们梳理下,这里面用到的三个主要的指针变量

head,它作为头,有背负数据走下去的重任!别随便修改它,小心被搞得晕头转向

prev在进行交换的时候启动

newp带新数据进入函数

p其实可以看作一个小head,不过它隔三岔五就会被改,而且在结束的时候也会被delete

那么我们就把这个Insert()的运作原理几乎讲完了,是把它里面数据变化的方式用一个字一个字的方式说出来,以后应该不会这么说了。

同时,合并部分我们还没说,下面小聊下,这个不是很关键

void Insert(Poly *newp)
	{
		Poly *prev=NULL, *p=Head;
		for(; p!=NULL; prev=p,p=p->next)
			if(p->index <= newp->index)
				break;
		if(p!=NULL && p->index==newp->index)
		{
			// 同类项;
			p->coef += newp->coef;
			delete newp;
			if(p->coef==0)
			{
				// 删除*p   删除*prev的后继结点;
				if(prev==NULL)
					Head      =p->next;
				else
					prev->next=p->next;
				delete p;
			}
		}
		else
		{
			// 在*p之前插入*newp  在*prev之后插入*newp
			newp->next=p; 
			if(prev==NULL)
				Head      =newp;
			else
				prev->next=newp;
		}
	}

最后我们聊下合并和ADD,Output等函数

(1)

如果指数相同,就把newp的系数给p,删了newp

然后排除0的情况,排除prev空,也就是没交换的情况,没了

(2)

add就是给个新空间装对象2,把对象2进行插入就行了

void Add(PolyList &L)
	{
		for(Poly *p=L.Head; p!=NULL; p=p->next)
		{
			Poly *newp =new Poly;	
			newp->coef=p->coef;  newp->index=p->index;
			Insert(newp);
		}
	}

(3)

output()就是head给一个新造的p,输出

void Output()
	{
		for(Poly *p=Head; p!=NULL; p=p->next)
			cout<<*p;
		cout<<endl;
	}

(4)

析构函数和removehead就不说了,用完把head放掉罢了

~PolyList()
	{//释放头节点;
		while(Head!=NULL)
			RemoveHead();
	}
	void RemoveHead()
	{
		Poly *p=Head;
		Head=Head->next;
		delete p;
	}

最后,完整给下源代码吧,感谢能一路读到这里的人

也许我用词不规范,但是道理应该不错的

#include <iostream>
#include <fstream>
using namespace std;
struct Poly
{
	int coef;
	int index;
	Poly *next;//多了个next域;
	friend ostream & operator<<(ostream &out, Poly &p)
	{
		return out<<p.coef<<" "<<p.index<<endl;
	}
};
class PolyList
{
	Poly *Head;
public:
	PolyList()
	{
		Head=NULL;
		
		int n; cin>>n;
		for(int i=0; i<n; i++)
		{
			Poly *newp =new Poly;	
			cin>>newp->coef>>newp->index;
			Insert(newp); // 按照指数降序插入*newp;
		}
	}
	// 按照指数降序插入*newp
	void Insert(Poly *newp)
	{
		Poly *prev=NULL, *p=Head;
		for(; p!=NULL; prev=p,p=p->next)
			if(p->index <= newp->index)
				break;
		if(p!=NULL && p->index==newp->index)
		{
			// 同类项;
			p->coef += newp->coef;
			delete newp;
			if(p->coef==0)
			{
				// 删除*p   删除*prev的后继结点;
				if(prev==NULL)
					Head      =p->next;
				else
					prev->next=p->next;
				delete p;
			}
		}
		else
		{
			// 在*p之前插入*newp  在*prev之后插入*newp
			newp->next=p; 
			if(prev==NULL)
				Head      =newp;
			else
				prev->next=newp;
		}
	}
	~PolyList()
	{//释放头节点;
		while(Head!=NULL)
			RemoveHead();
	}
	void RemoveHead()
	{
		Poly *p=Head;
		Head=Head->next;
		delete p;
	}
	void Add(PolyList &L)
	{
		for(Poly *p=L.Head; p!=NULL; p=p->next)
		{
			Poly *newp =new Poly;	
			newp->coef=p->coef;  newp->index=p->index;
			Insert(newp);
		}
	}
	void Output()
	{
		for(Poly *p=Head; p!=NULL; p=p->next)
			cout<<*p;
		cout<<endl;
	}
};
int main()
{
	PolyList  L1;  
	PolyList  L2;
	L1.Add(L2);				 L1.Output();
	return 0;
}

二,括号的匹配

坏了,我已经写不动了

自定义栈结构,及其基本运算。
设计函数Match(……),判断字符串中的圆括号的匹配情况。
编写main()函数,读入一个字符串(长度小于1000),调用Match等函数。
若左右圆括号匹配,则输出"ok";
若左括号多于右括号,则输出"left"及所有失配的左括号的下标;
若右括号多于左括号,则输出"right"及第一个失配的右括号的下标。

测试案例1:
输入:

((a+b)*(c+d))

输出:

ok

测试案例2:

输入:

a+((a+b)*((c+d)+z

输出:

left 9 2

输出案例3:

输入:

(a+b)*(c+d))

输出:

right 11

简单概括下思想,就是左括号进栈,右括号出栈,最后检测栈内状况

直接丢代码吧,啊啊啊,我要死了。。。

#include<iostream>
#include <string>
using namespace std;
class LinkStack
{
	char stack[1024];
	int top = 1024;
	bool gg = true;//判断是否需要进行ok和left
public:
	LinkStack(){}
	~LinkStack() {}
	void push(char x)
	{
		top--;
		stack[top] = x;
	}
	int pop()
	{//删除栈顶数据;
		char x = stack[top];
		top++;
		return x;
	}
	bool empty()
	{
		if (top == 1024)
			return 1;
		return 0;
	}
	//设计函数Match(……),判断字符串中的圆括号的匹配情况。;
	void Match(char *x)
	{
		int n = 0,i=0,j=0;
		int b[20],c[20];
		while (*x != '\0')
		{
			
			char L = '/0';//左括号
			char R = '/0';//右括号
			char ch = *x;
			switch (ch)
			{
			case'(':
				push(ch);
				i++;
				b[i] = n;
				if (j > 0)
					j--;
				break;
			case')':
				L = '(';
				R = ch;
				break;
			default:
				break;

			}
			n++;
			if (R == ch)//11111111111
			{
				if (empty()==false)
				{
					char t = pop();//出栈
					i--;
					j++;
					if (j != 0)
						c[j] = n;
				}
				else
				{
					cout << "right"<<" ";
					for (; j > 0; j--)
						cout << c[j] << " ";
					cout << endl;
					gg = false;
				}
			}
			x++;
		}
		if (gg == true)
		{
			if (int a = empty() == true)
				cout << "ok" << endl;
			else
			{
				cout << "left" <<" ";//
				for (;i>0;i--)
					cout << b[i]<<" ";
				cout << endl;
			}
		}
	}
};
int main()
{
	char a[1024];
	cin >> a;
	LinkStack s;
	s.Match(a);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值