数据结构、算法及线性表总结
数据结构、算法及线性表总结
一、思维导图
二、重要概念的总结
1.时间复杂度的求法
例题求时间复杂度:
int i, j, num1, num2;
for(i=0; i<n; i++){
num1 += 1;
for(j=1; j<=n; j++){
num2 += num1;
}
}
分析:
语句int i, j, num1, num2;的频度为1;
语句i=0;的频度为1;
语句i<n; i++; num1+=1; j=1; 的频度为n;
语句j<=n; j++; num2+=num1;的频度为nn;
T(n) = 2 + 4n + 3nn
所以时间复杂度是:O(n²)
*常见时间复杂度:
(1)O(1):常量阶,运行时间为常量
(2)O(n):线性阶,如n个数内找最大值
(3)O(logn):对数阶,如二分搜索算法
(4)O(nlogn):对数阶,如快速排序算法
(5)O(n²):平方阶,如选择排序,冒泡排序
(6)O(n³):立方阶,如两个n阶矩阵的乘法运算
(7)O(2ⁿ):指数阶,如n个元素集合的所有子集的算法
(8)O(n!):阶乘阶,如n个元素全部排列的算法
------->附网上找的时间复杂度变化曲线
2.链表的创建
*定义说明
typedef struct LNode //定义单链表结点类型
{
ElemType data;
struct LNode *next; //指向后继结点
} LNode,*LinkList;
1)头插法
void CreateListF(LinkList &L,int n){
int i;
LinkList s;
L=new LNode;
L->next = NULL;
for (i = 0; i < n; i++) {
s = new LNode;
cin >> s->data;
s->next = L->next;
L->next = s;
}
}
2)尾插法
void CreateListR(LinkList& L, int n) {
LinkList s, r;
int i;
L = new LNode;
r = L;
for (i = 0; i < n; i++) {
s = new LNode;
cin >> s->data;
r->next = s;
r = s;
}
r->next = NULL;
}
3.用栈实现括号匹配检验
1)分析:
输入一个表达式,凡出现左括弧,则进栈,凡出现右括弧,首先检查栈是否为空,若栈空,则表明该“右括弧”多余,否则和栈顶元素比较,若相匹配,则“左括弧出栈” ,否则表明不匹配,表达式检验结束时,若栈空,则表明表达式中匹配正确,否则表明“左括弧”有余
2)代码实现:
#include <iostream>
#include <cstring>
#include <stack>
using namespace std;
void print(char ch) {
if (ch == '(') printf("(-?\n");
else if (ch == '[') printf("[-?\n");
else if (ch == '{') printf("{-?\n");
else if (ch == '<') printf("/*-?\n");
}
int main() {
char str[1000];
stack <char> s;
int flag = 1, i;
while (1) {
scanf("%s", str);
if (str[0] == '.' && str[1] == 0) break;
for (i = 0; str[i]; i++) {
if (flag == 0) break;
if (str[i] == '(' || str[i] == '[' || str[i] == '{') {
s.push(str[i]);
}
else if (str[i] == '/' && str[i + 1] == '*') {
s.push('<');
i++;
}
else if (str[i] == ')') {
if (!s.empty() && s.top() == '(') s.pop();
else {
printf("NO\n");
flag = 0;
if (s.empty()) {
printf("?-)\n");
}
else {
print(s.top());
}
break;
}
}
else if (str[i] == ']') {
if (!s.empty() && s.top() == '[') s.pop();
else {
printf("NO\n");
flag = 0;
if (s.empty()) {
printf("?-]\n");
}
else {
print(s.top());
}
break;
}
}
else if (str[i] == '}') {
if (!s.empty() && s.top() == '{') s.pop();
else {
printf("NO\n");
flag = 0;
if (s.empty()) {
printf("?-}\n");
}
else {
print(s.top());
}
break;
}
}
else if (str[i] == '*' && str[i + 1] == '/') {
i++;
if (!s.empty() && s.top() == '<') s.pop();
else {
printf("NO\n");
flag = 0;
if (s.empty()) {
printf("?-*/\n");
}
else {
print(s.top());
}
break;
}
}
}
}
if (flag && s.empty()) printf("YES\n");
else if (flag) {
printf("NO\n");
print(s.top());
}
return 0;
}
4.关于队列一些判断的总结:
1)顺序队列运算时的头、尾指针变化条件
空队列:Q.front==Q.rear
队列满:Q.rear-Q.front=m
入队: Q.base[rear++]=x
出队:x=Q.base[front++]
2)循环队列队满和队空的判断
队空:Q.rear = Q.front
队满:(Q.rear+1) % m = Q.front
5.next数组的求法
串: a b c a b a a
next: 0 1 1 1 2 3 2
以上面的为例,next值本身的含义即是当进行匹配的模式串发生失配后,失配的这一字符再次进行匹配时要与哪个字符再进行比较?我们可以理解为这次配不上,那我下次和谁比?这样,next的值就与T发生了关系,表示了字符的比较位置。T就是元素的位置。
开始不用说,a前面没有,就是0,b要和a比,a的位置是1,b就是1。简单说,开头两个肯定是0,1
第三个,c,c的前面是b,bc无法与开头的a比,所以c还是要单独找位于1的a,所以它也是1
第四个,a,和第三个c一样,没有可以满足ca的字符串,最后a只能自己和第一个a配,它也是1
第五个,b,看b前面,正好,a可以与开头的a对上,而第五个b正好在2的位置,所以b就是2
第六个,a,看a前面,发现,a前面的ab可以与开头的ab对上,对上后,第六个a在位置3,所以就是3
第七个,a,看a前面,只有a能够与开头配上,而“baa”则不行,所以它只有为2
由此可以看出,next的计算,实际上就是计算当前字符以及当前字符前面的字符与开头匹配成功后,当前字符的最终位置,如果不成,就只能单独找第1个,所以它的值只能为1。