第二周总结
**
一、栈
**
1.定义:
栈是一种操作受限制的线性表。将允许进行插入、删除的一端称为栈顶,另一端称为栈底。
2.分类:
栈主要分为静态栈和动态栈,静态栈类似于数组,动态栈类似于链表,但只能对链表的一端进行操作。
3.表示:
#define stack_size 100
typedef int SDataType;//假设栈内元素为整型。
typedef struct stack
{
SDataType array[stack_size];
int top;
}stack;
4.操作:
#ifndef STACK_H_
#define STACK_H_
#include<assert.h>
#include<stdio.h>
#define Max_Size 100
typedef int SDataType;
typedef struct Stack
{
SDataType array[Max_Size];
int top;
}Stack;
//初始化
void InitStack(Stack *s)
{
s->top = 0;
}
//打印
void PrintS(Stack s)
{
if (s.top == 0)
{
printf("空栈\n");
return;
}
int i = 0;
for (; i < s.top; i++)
{
printf("%d ", s.array[i]);
}
printf("\n");
}
//销毁
void StackDestroy(Stack *s)
{
s->top = 0;
}
//入栈
void StackPush(Stack *s,SDataType data)
{
assert(s->top < Max_Size);
s->array[s->top++] = data;
}
//出栈
void StackPop(Stack *s)
{
assert(s->top > 0);
s->top--;
}
//判断是否是空栈,是,返回1;不是,返回0.
int Isempty(Stack s)
{
if (s.top == 0)
{
return 1;
}
else
{
return 0;
}
}
//返回栈内元素的个数
int Scount(Stack s)
{
return s.top;
}
//取栈顶元素
SDataType TopStack(Stack s)
{
if (s.top == 0)
{
return -1;
}
return s.array[s.top - 1];
}
void test1()
{
Stack s;
InitStack(&s);
StackPush(&s, 1);
//StackPop(&s);
PrintS(s);
StackDestroy(&s);
PrintS(s);
//printf("%d\n",TopStack(s));
}
#endif
二、队列
概念:
只允许在一端插入数据操作,在另一端进行删除数据操作的特殊线性表;进行插入操作的一端称为队尾(入队列),进行删除操作的一端称为队头(出队列);队列具有先进先出(FIFO)的特性。
代码模板
//LQueue.h
typedef int QElemType;
//typedef struct BTNode* QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *_pNext;
}QNode;
typedef struct LQueue
{
QNode *pFront;
QNode *pRear;
}LQueue;
//初始化
void LQueueInit(LQueue *q);
//入队列
void LQueuePush(LQueue *q, QElemType data);
//出队列
void LQueuePop(LQueue *q);
//返回队头元素
QElemType LQueueTop(LQueue *q);
//返回返回队列长度
int LQueueSize(LQueue *q);
//队列是否为空
int LQueueEmpty(LQueue *q);
/************************************************/
//LQueue.c
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
//创建新结点
static QNode *BuyLQNode(QElemType data)
{
QNode *pLQNode = (QNode *)malloc(sizeof(QNode));
if (NULL == pLQNode)
{
printf("申请空间失败!\n");
assert(pLQNode);
}
pLQNode->data = data;
pLQNode->_pNext = NULL;
return pLQNode;
}
//初始化
void LQueueInit(LQueue *q)
{
assert(q);
q->pFront = q->pRear = NULL;
}
//入队列
void LQueuePush(LQueue *q, QElemType data)
{
assert(q);
if (NULL == q->pFront)
{
q->pFront = q->pRear = BuyLQNode(data);
return;
}
q->pRear->_pNext = BuyLQNode(data);
q->pRear = q->pRear->_pNext;
}
//出队列
void LQueuePop(LQueue *q)
{
assert(q);
QNode *pDel;
if (NULL == q->pFront)
{
return;
}
if (q->pFront == q->pRear)
{
q->pRear = NULL;
}
pDel = q->pFront;
q->pFront = q->pFront->_pNext;
free(pDel);
}
//返回队头元素
QElemType LQueueTop(LQueue *q)
{
assert(q);
return q->pFront->data;
}
//返回队尾元素
QElemType LQueueBack(LQueue *q)
{
assert(q);
return q->pRear->data;
}
//返回返回队列长度
int LQueueSize(LQueue *q)
{
int count = 0;
QNode *pCur;
assert(q);
pCur = q->pFront;
while (pCur)
{
pCur = pCur->_pNext;
count++;
}
return count;
}
//队列是否为空
int LQueueEmpty(LQueue *q)
{
return NULL == q->pFront;
}
三、串
1、概念
字符串简称串,是一种特殊的线性表,它的数据元素仅由一个字符组成。
2、定义
串(String)是由零个或多个字符组成的有限序列,又称字符串。
3、代码模板
#define MAXLEN 10
typedef struct
{
char vec[MAXLEN];
int len;
} Str;//可用Str来定义该类型的结构体变量
四、stack与queue
**
stack
**
1、stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。
2、stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
3、stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作
代码模板
template <class T, class Container = deque<T>>
class Stack
{
public:
void Push(const T& x)
{
_con.push_back(x);
}
void Pop()
{
_con.pop_back();
}
T& Top()
{
return _con.back();
}
const T& Top() const
{
_con.back();
}
size_t Size()
{
return _con.size();
}
bool Empty()
{
return _con.empty();
}
private:
Container _con;
};
int main()
{
// 适配体现在第二个模板参数可以使用不同的容器,然后适配生成的stack效果是一样的。
//Stack<int, deque<int>> st;
//Stack<int, vector<int>> st;
//Stack<int, list<int>> st;
Stack<int> st;
st.Push(1);
st.Push(2);
st.Push(3);
st.Push(4);
st.Push(5);
while (!st.Empty())
{
cout << st.Top() << " ";
st.Pop();
}
cout << endl;
return 0;
}
queue
1、队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
2、队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
3、底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列
代码模板
template <class T, class Container = deque<T>>
class Queue
{
public:
void Push(const T& x)
{
_con.push_back();
}
void Pop()
{
_con.pop_front();
}
T& Front()
{
return _con.front();
}
size_t Size()
{
return _con.size();
}
bool Empty()
{
return _con.empty();
}
T& Back()
{
return _con.back();
}
private:
Container _con;
};
int main()
{
//适配体现在第二个模板参数可以使用不同的容器,然后适配生成的queue效果是一样的。
//Queue<int, deque<int>> q;
//Queue<int, list<int>> q;
Queue<int, deque<int>> q;
q.Push(1);
q.Push(2);
q.Push(3);
q.Push(4);
q.Push(5);
while (!q.Empty())
{
cout << q.Front() << " ";
q.Pop();
}
cout << endl;
return 0;
}
五、二分
二分查找法主要用于“一堆数中找出指定的数”问题
代码实现
#include<iostream>
using namespace std;
#include<cstdio>
#include<cmath>
#include<cstdlib>
#define inf 2000000000
#define ll long long
inline ll f(ll x)
{
return x*(log(x)/log(10))+1;/*求位数的公式,n进制,n就做log的底数,别忘了加1*/
}
int main()
{
ll l=1,r=inf;
ll n;
cin>>n;
while(1)
{
ll mid=(l+r)>>1;
if(f(mid)>=n) r=mid;/*确定好二分的边界*/
else l=mid+1;
if(l==r)
{
cout<<l<<endl;
break;
} }
return 0;
}
六、前缀与差分
前缀和
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], s[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ ) s[i] = s[i - 1] + a[i]; // 前缀和的初始化
while (m -- )
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", s[r] - s[l - 1]); // 区间和的计算
}
return 0;
}
二维前缀和
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int s[N][N];
int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &s[i][j]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
while (q -- )
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
}
return 0;
}
一维差分
B[i] = a[i] - a[i - 1]
给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int a[N], b[N];
void insert(int l, int r, int c)
{
b[l] += c;
b[r + 1] -= c;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++ ) insert(i, i, a[i]);
while (m -- )
{
int l, r, c;
scanf("%d%d%d", &l, &r, &c);
insert(l, r, c);
}
for (int i = 1; i <= n; i ++ ) b[i] += b[i - 1];
for (int i = 1; i <= n; i ++ ) printf("%d ", b[i]);
return 0;
}
二维差分
// 给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
// S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] +=
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
scanf("%d", &a[i][j]);
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
insert(i, j, i, j, a[i][j]);
while (q -- )
{
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
b[i][j] += b[i - 1][j] + b[i][j - 1] - b[i - 1][j - 1];
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= m; j ++ ) printf("%d ", b[i][j]);
puts("");
}
return 0;
}
七、位运算
概述
从现代计算机中所有的数据二进制的形式存储在设备中。即0、1两种状态,计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。
按位与(&)
按位或(|)
按位异或(^)
按位取反(~)
按位左移(<<)
按位右移(>>)