线性表--栈-1

文章目录

  • 主要内容
  • 一.栈基础练习题
      • 1.设链表不带头结点且所有操作均在表头进行,则下列最不适合作为链栈的是 ( C )。
          • 解析如下(示例):
      • 2.一个栈的入栈序列为 1,2,3,..,n,出栈序列是P1,P2,P3,...,Pn。若P2=3,则P3可能取值的个数是( C )
          • 解析如下(示例):
      • 3.假设以I和 0分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和 O组成的序列,可以操作的序列称为合法序列,否则称为非法序列。
          • 代码如下(示例):
      • 4.设单链表的表头指针为L,结点结构由 data 和 next 两个域构成,其中 data 域为字符型。试设计算法判断该链表的全部 n 个字符是否中心对称。例如 xyx、xyyx 都是中心对称。
          • 代码如下(示例):
  • 总结

主要内容

  1. 栈基础练习题

一.栈基础练习题

1.设链表不带头结点且所有操作均在表头进行,则下列最不适合作为链栈的是 ( C )。

A.只有表头结点指针,没有表尾指针的双向循环链表
B.只有表尾结点指针,没有表头指针的双向循环链表
C.只有表头结点指针,没有表尾指针的单向循环链表
D.只有表尾结点指针,没有表头指针的单向循环链表

解析如下(示例):
对于双向循环链表,不管是表头指针还是表尾指针,都可以很方便地找到表头结点,方便在表头做插入或删除操作。
而单循环链表通过尾指针可以很方便地找到表头结点,但通过头指针找尾结点则需要遍历一次链表。
对于 C,插入和删除结点后,找尾结点需要花费 O(n的时间。

2.一个栈的入栈序列为 1,2,3,…,n,出栈序列是P1,P2,P3,…,Pn。若P2=3,则P3可能取值的个数是( C )

A.n-3
B.n-2
C.n-l
D.无法确定

解析如下(示例):
显然,3 之后的4,5...n 都是P3可取的数(持续进直到该入后立即出)。
接下来分析12:P1可以是3之前入的数 (可能是12),也可以是4,
当P=1时,P3可取2:当P=2时,P3可取1;当P=4时,P3可取除134之外的所有数;
故P可能取值的个数为n-1

3.假设以I和 0分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和 O组成的序列,可以操作的序列称为合法序列,否则称为非法序列。

1)下面所示的序列中哪些是合法的?
A.OIIOIOO
B.IOOIOIIO
C.IIIOIOIO
D.IIIOOIOO
2) 通过对 1)的分析,写出一个算法,判定所给的操作序列是否合法。若合法,返回true,否则返回 false(假定被判定的操作序列已存入一维数组中)。

代码如下(示例):
1)A、D合法,而B、C不合法。
在B 中,先入栈1次,再连续出栈2次,错误。
在C中,入栈和出栈次数不一致,会导致最终的栈不空。
A、D 均为合法序列。
注意:入栈次数一定大于等于出栈次数;结束时,栈一定为空。
2)设被判定的操作序列已存入一维数组 A 中。
算法的基本设计思想:依次逐一扫描入栈出找序列(即由“I”和“O”组成的字符串),
每扫描至任一位置均需检查出栈次数(即“O”的个数)是否小于入栈次数(“I”的个数,若大于则为非法序列。
扫描结束后,再判断入栈和出栈次数是否相等,若不相等则不合题意,为非法序列。
int Judge(char Al ]){
//判断字符数组A中的输入输出序列是否是合法序列。如是,返回true,否则返回false
	int i=0;
	int j=k=0;  //i为下标,i和k分别为字母I和O的个数
	while(A[i]!='\0'){  //未到字符数组尾
		switch(A[i]){
			case 'I':j++; break;  //入栈次数增1
			case 'O': k++;
				if(k>j){printf("序列非法\n");exit(0);}
		}
		i++;  //不论A[i]是“I”或“o”,指针均后移
	}  //while
	if(j!=k){
		printf("序列非法\n");
		return false;
	}
	else{
		printf("序列合法\n");
		return true;
	}
}

[另解]入栈后,栈内元素个数加 1:出栈后,栈内元素个数减 1,
因此可将判定一组出入栈序列是否合法转化为一组由+1-1组成的序列,
它的任意前缀子序列的累加和不小于0(每次出栈或入栈操作后判断)则合法;否则非法。

4.设单链表的表头指针为L,结点结构由 data 和 next 两个域构成,其中 data 域为字符型。试设计算法判断该链表的全部 n 个字符是否中心对称。例如 xyx、xyyx 都是中心对称。

代码如下(示例):
算法思想:使用核米判断链表中的数据是否中心对称。让链表的前一半元素依次进栈。
在处理链表的后一半元素时,当访问到链表的一个元素后,就从栈中弹出一个元素,两个元素比较,
若相等,则将链表中的下一个元素与栈中再弹出的元素比较,直至链表到尾。
这时若栈是空栈,则得出链表中心对称的结论;
否则,当链表中的一个元素与栈中弹出元素不等时,结论为链表非中心对称,结束算法的执行。
int dc(LinkList L,int n){  
// 是带头结点的n个元素单链表,本算法判断链表是否是中心对称
	int i;  
	char s[n/2];  //s字符栈
	p=L->next;  //p是链表的工作指针,指向待处理的当前元素
	for(i=0;i<n/2;i++){  //链表前一半元素进栈
		s[i]=p->data;
		p=p->next;
		}
	i--;  //恢复最后的i值
	if(n%2==1)  //若n 是奇数,后移过中心结点
		p=p->next;
	while(p!-NULL&&s[il==p->data){ //检测是否中心对称 
		i--;  //i 充当栈顶指针
		p=p->next;
	}
	if(i==-1) //栈为空栈
		return 1;  //链表中心对称
	else
		return 0;  //链表不中心对称
}
算法先将“链表的前一半”元素(字符)进栈。当n为偶数时,前一半和后一半的个数相同;
当n为奇数时,链表中心结点字符不必比较,移动链表指针到下一字符开始比较。
比较过程中遇到不相等时,立即退出 while循环,不再进行比较。
本题也可以先将单链表中的元素全部入栈,然后扫描单链表 L 并比较,直到比较到单链表L尾为止,
但算法需要两次扫描单链表 L,效率不及上述算法高。

总结

以上是今天要讲的内容,练习了线性表–栈相关练习题。

你可能感兴趣的:(算法与数据结构,c语言,算法,数据结构,vscode)