考研数据结构(2)笔记

数据结构(1)链接https://blog.csdn.net/Z_timer/article/details/105595519(多图预警)

数据结构(3)链接https://blog.csdn.net/Z_timer/article/details/113867898

目录

栈、队列

栈(stack)

队列(queue)

考点总结

输出序列

表达式转换

判断空满的问题

双端队列

栈的扩展

串的基本操作

KMP算法

数组、矩阵、广义表

数组

特殊矩阵和稀疏矩阵

广义表


栈、队列

栈(stack)

先进后出

栈是一种只能在一端进行插入或删除操作的线性表

存储结构:顺序栈、链栈。

顺序栈: int stack[maxSize]; int top = -1; stack[++top]  = 值; 元素入栈 。 x = stack[top--];  元素出栈(top在哪里,栈就在哪里虽然没有删除该数值,但top已经后移一位,在栈里删除了该值,实际存储空间里还有后续只要入栈就会覆盖当前值)

判断栈的情况


链栈

队列(queue)

先进先出FIFO

存储结构:顺序队、链队

顺序队(循环队):(规定:入队 先移动“队尾指针”再入队元素,出队 先移动“对头指针”再出队元素,队空状态 front = rear时为空)

入队:queue[++rear] = x;  出队:x = queue[++front];

(会造成假溢出,即rear在最后一位,但是前面的front已经离开了第0位,rear再往前走会造成数据溢出,需要弄成一个“环”。)

     

(%取余数)队空:front == rear 为 True


链队:

结构体里存指针,为空就是front为空的时候

考点总结

输出序列

由下可知,出栈从3开始,因此入栈到1、2、3结束;然后出3,4,出4,出2,出1,至此栈内无元素,入栈5、6,后发现栈的容量为3(注意画图和栈的特性先进后出)

408 09年2题。   注意队列是先进先出,所以出队序列就是出栈序列,不会影响。由出栈序列b可知,入a,b,栈容量2,出b,留a;序列d可知,入c、d,栈容量3,出d,留a、c;。。。可知答案为3

此考点多做题就好,参考https://blog.csdn.net/Z_timer/article/details/109599781---队列的3、5、7题。

表达式转换

中缀表达式:a+b、前缀表达式(波兰式):+ab、后缀表达式(逆波兰式):ab+

中缀转前后缀

方法:加括号和花操作树,注意运算次序,先括号,后乘除最后加减。此处加括号(参考https://blog.csdn.net/Z_timer/article/details/109599781---队列的2、4、6)里体会,操作树跟加括号差不多,只是更清楚明白。

由中缀画出操作树后根据前后缀,分别用前序遍历或者后序遍历即可。

后缀转中缀

注:非运算符算一个表达式,括号括起来的内容也算表达式。两个表达式加运算符把运算符移到表达式中间即可。

1. 由ab+可知,ab为表达式,+为运算符,由此得:(a+b)

2. 由(a+b)c*可知,(a+b)c为表达式,*为运算符,由此得:((a+b)*c)

3. 省略到 (((a+b)*c)+d)eg+h*-

4. 由(((a+b)*c)+d)eg+可知,选择距离运算符最近的两个表达式,得eg+转化为e+g

5. 由(((a+b)*c)+d)(e+g)h*可知(e+g)h为表达式,*为运算符,由此得:(e+g)*h

6. (((a+b)*c)+d)(e+g)*h-可知,(((a+b)*c)+d)为表达式(e+g)*h为表达式,-为运算符,最后去掉不必要的括号得((a+b)*c)+d-(e+g)*h

后缀转前缀

同中缀,只不过把运算符放到最前面

中缀转后缀---栈实现

     操作数顺序不变,将运算符进行排序

  1. 将栈初始化为空栈;
  2. 从左到右扫描表达式的每一个字符,执行下面操作:

    2.1  遇到操作数:直接输出(添加到后缀表达式中)

    2.2  栈为空时,遇到运算符,直接入栈

    2.3  遇到左括号:将其入栈

    2.4  遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。

    2.5  遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈

    2.6  最终将栈中的元素依次出栈,输出。

https://www.cnblogs.com/wkfvawl/p/12864789.html

例题:A

中缀转前缀---栈实现

https://cloud.tencent.com/developer/article/1596127

中缀转前缀表达式思路

基本同中转后相同,不同点:

1、上面的从左到右扫描表达式,改成从右向左扫描每一个字符。

2、左括号和右括号的判断和上面相反。

后缀转前缀---栈实现

 

结束

每次遇到一个运算符,把相邻的两个表达式放在运算符后面

中缀转前、后缀代码:

https://blog.csdn.net/Z_timer/article/details/111316815

求中缀值代码:

计算3+4*5*(2+3)

1. 栈1:3 4 5 top1(栈顶指针)

    栈2:+ *['*' > '+', 所以入栈,必须大于]

2. 栈1:3 20(4*5 注意顺序) top2(栈顶指针)

    栈2:+ * ['*' == '*' 所以第一个*出栈 ]

3. 栈1:3 20 2 3

    栈2:+ * ( +

4. 栈1:3 20 5(2+3 注意顺序)

    栈2:* + 

5. 栈1:3 100(20*5)

    栈2:+

6. 103

int getPriority(char op) {
	if (op=='+' || op=='-') return 0;
	else return 1;
}

int calSub(float opand1, char op, float opand2, float &result) {
	if (op == '+') result = opand1 + opand2;
	if (op == '-') result = opand1 - opand2;
	if (op == '*') result = opand1 * opand2;
	if (op == '/') {
		if (fabs (opand2) < Min) return 0; // 判断是否为0,不能用==0 因为会存在bug具体百度,
		//Min代表一个趋近于0的值
		else result = opand1 / opand2;
	}
	return 1; // 不返回result是因为判断数据是否合法 0否1是
}
float calInfix(char exp[]) {
	float s1[maxSize];
	int top1 = -1;
	float s2[maxSize];
	int top2 = -1;
	int i=0;
	while (exp[i] != '\0') {
		if ('0' <= exp[i] && exp[i] <= '9') {	//数字进操作数栈
			s1[++top1] = exp[i] - '0'; // 转化为数字
			++i;
		} else if (exp[i] == '(') {	//左括号直接放入运算栈,待下次判断右括号
			s2[++top2] = '(';
			++i;
		} else if (exp[i]=='+' ||
		           exp[i]=='-' ||
		           exp[i]=='*' ||
		           exp[i]=='/') {	//判断运算符
			if (top2==-1||
			        s2[top2]=='('||
			        getPriority(exp[i]) > getPriority(s2[top2])) {
				s2[++top2] = exp[i];	//运算符栈为空、左括号、优先级比栈内元素大 都可直接入运算栈
				++i;
			} else {
				float opnd1, opnd2, result;
				char op;
				int flag;
				opnd2 = s1[top1--]; // 注意操作数赋值顺序
				opnd1 = s1[top1--];
				op = s2[top2--];
				flag = calSub(opnd1, op, opnd2, result);
				if (flag == 0) {
					std::cout << "ERROR" << std::endl;
					return 0;
				}
				s1[++top1] = result;
			}
		} else if (exp[i] == ')') {	//左括号直接全部放入输出栈
			while (s2[top2] != '(') {
				float opnd1, opnd2, result;
				char op;
				int flag;
				opnd2 = s1[top1--]; // 注意操作数赋值顺序
				opnd1 = s1[top1--];
				op = s2[top2--];
				flag = calSub(opnd1, op, opnd2, result);
				if (flag == 0) {
					std::cout << "ERROR" << std::endl;
					return 0;
				}
				s1[++top1] = result;
			}
			--top2;	//弹出'('
			++i;
		}
	}
	while (top2 != -1) {
		float opnd1, opnd2, result;
		char op;
		int flag;
		opnd2 = s1[top1--]; // 注意操作数赋值顺序
		opnd1 = s1[top1--];
		op = s2[top2--];
		flag = calSub(opnd1, op, opnd2, result);
		if (flag == 0) {
			std::cout << "ERROR" << std::endl;
			return 0;
		}
		s1[++top1] = result;
	}
	return s1[top1];
}
// 此处三处代码一模一样,有需求的直接整合成函数,然后调用函数即可 ps考试不会这么长代码 

求前后缀的值就不多加赘述了,只用把操作数(表达式)入栈,遇到运算符出两个操作数,运算结果放入栈中即可。

判断空满的问题

正常情况下:队空:front == rear;队满:front == (rear+1) %maxSIze

在该情况下元素个数计算

非正常情况下

1. 入队出队的代码顺序相反

但是队空、队满、计算元素个数同上

2. 

例题:

双端队列

什么是双端队列:https://www.bilibili.com/s/video/BV1754y1d7yh

题:https://my.oschina.net/gouqizi12/blog/4414498

栈的扩展

共享栈

栈1为空top[0] == -1,栈2为空top[1] == maxSize;

S1入栈:stack[++top[0]] = x;S2入栈:stack[--top[1]] = x;

栈满:top[0] + 1 == top[1]

用栈模拟队列

括号匹配

https://leetcode-cn.com/problems/valid-parentheses/solution/

计算问题


串是特殊的线性表,每个单元都是一个字符。

   

// 不定长存储结构 便于动态分配内存
Str S;
S.length = L;
S.ch = (char*)malloc((L+1)*sizeof(char)); // 此处动态分配
S.ch[length范围内的下标] = 某字符/变量;
某字符/变量 = S.ch[length内的下标];
free(S.ch); //直接清空数据

串的基本操作

赋值操作

int StrAssign(Str &str, char *ch){
    if (str.ch) free(str.ch); // 清空原数据
    int len = 0;
    char *c = ch;
    while (*c){ // 获取该字符串的个数,到'\0'结束 len不包括'\0'
        ++len;
        ++c;
    }
    if (len == 0){
        str.ch = NULL;
        str.length = 0;
        return 1;
    }
    str.ch = (char*)malloc(sizeof(char)*(len+1));
    if (str.ch == NULL) return 0; // 判断分配内存是否失败
    else {
        c = ch;
        for (int i=0; i<=len; ++i,++c)
            str.ch[i] = *c;
        str.length = len;
        return 1;

    }
}
// string.h里的strcpy 

取串长度

int strLength (Str str){ return str.length; }

串比较

int strCompare (Str s1, Str s2){
    for (int i=0; i<s1.lenght && i<s2.length; ++i){
        if (s1.ch[i] != s2.ch[i])
            return s1.ch[i] - s2.ch[i]; // 两个字符串不相等则返回相减值 判断谁大谁小
        return s1.length - s2.length; // 判断字符串长度,谁大谁小 
    }
}

串连接

int concat(Str &str, Str str1, Str str2){
    if (str.ch){
        free(str.ch);
        str.ch = NULL;
    }
    str.ch = (char*)malloc(sizeof(char)*(str1.length + str2.length+ 1));
    if (!str.ch) return 0;
    int i = 0;
    while (i < str1.length){
        str.ch[i] = str1.ch[i];
        ++i;
    }
    int j = 0;
    while (j < str2.length){
        str.ch[i+j] = str2.ch[j]; // i+j从str1末尾继续赋值
        ++j;
    } 
    str.length = str1.length + str2.length;
    return 1;
}

求子串

关键操作:

清空字符串

int  clearString(Str &str) {
    if (str.ch){ 
        free(str,ch);
        str.ch = NULL;
    }
    str.length = 0;
    return 1;
}

KMP算法

建议看这里 https://blog.csdn.net/Z_timer/article/details/109599781#t13的题目和解析,应该有两三个视频。

代码:


数组、矩阵、广义表

408不常考,非统考基本考下标

数组

注意下标与实际差一即可。以及列优先、行优先。推荐参考这里的题目https://blog.csdn.net/Z_timer/article/details/109599781#t17

特殊矩阵和稀疏矩阵

特殊矩阵

对称矩阵、三角矩阵、对角矩阵

稀疏矩阵

三元组表示法第一行存储5个数字,4行4列

邻接表表示法

十字链表表示法

广义表

逻辑结构

广义表的长度:为表中最上层元素的个数。如广义表C长度为2,注意不是3.

广义表的深度:为表中括号的最大层数。求深度时可将子表展开,如D应为 ((d, e), (b, (c, d))), 由绿色可知有三层,所以深度为3

表头(Head)表尾(Tail):当广义表非空时,第一个元素为表头,其余元素组成的表是广义表的表尾。

考试一般采用这种形式:getHead(B) = d;   getTail(B) = (e)  // 其中函数不用具体实现,知道getHead取表头,getTail取表尾即可,注意表尾有括号,因为取出来为广义表

getHead(D) = B;  getTail(D) = (C) // B、D为上表中的数据

getHead((a)) = (a); getTail((a)) = () // 其中(a) 指一个广义表,我也不清楚为什么getHead的结果要加括号

存储结构

(1代表表节点,0代表原子节点,下面的ABCDE都是上面的图中的数据)

扩展线性表存储结构

猜你喜欢

转载自blog.csdn.net/Z_timer/article/details/106457448
今日推荐