数据结构
1 C++标准库STL常用介绍
1.1 map
map可以将任何基本类型 (键key) 映射到任何基本类型 (值value)。
1.1.1 准备工作
#include< map> ; using namespace std;
1.1.2 定义
map< string,int > mp; 字符串(键) 到 整型(值) 的映射,键是唯一的。
1.1.3 使用
(1) 基本访问
#include<stdio.h>
#include<map>
using namespace std;
int main(){
map<char,int> mp;
mp['c']=20;
mp['c']=30;//20被覆盖
printf("%d\n",mp['c']);//输出30
return 0;
}
(2) 迭代器访问
#include<stdio.h>
#include<map>
using namespace std;
int main(){
map<char,int> mp;
mp['m']=20;
mp['r']=30;
mp['a']=40;
for(map<char,int>::iterator it = map.begin(); it !=mp.end(); it++){
printf("%c %d\n",it -> first,it -> second);
}
return 0;
}
输出结果:(map会自动按照键的大小排序)
a 40
m 20
r 30
(3) find() /erase()
mp.find(key) 返回键为key的映射迭代器。
mp.erase(key) 删除键为key的映射,
mp.erase(first,last) 删除first-last区间内的映射。
#include<stdio.h>
#include<map>
using namespace std;
int main(){
map<char,int> mp;
mp['a']=1;
mp['b']=2;
mp['c']=3;
map<char,int>::iterator it = map.find('b');
//mp.erase(it);//删除it映射,即b 2
//mp.erase(it,mp.end());//删除it 之后的所有映射
printf("%c %d\n",it -> first,it -> second);
return 0;
}
输出结果:
b 2
1.2 queue() 队列 先进先出
从队尾加入,队头移除。
简单图示:
1.2.1 准备工作
#include< queue> ; using namespace std;
1.2.2 定义
queue< int > vi;
1.2.3 直接使用
(1) 入队 push(x)
vi.push(x) 将x放入队列,先放为队首,后放为队尾
(2) 出队 pop()
vi.pop() 将元素出队,从队首开始出。
(3) 访问队首、队尾 front()、back()
vi.front():访问队首元素;
vi.back():访问队尾元素。
(4) 获取队列大小 size()
vi.size() 返回队列内元素个数。
(5) 判空 empty()
vi.empty() 返回bool类型值。
1.2.4 应用-非标准库
下面用数组q[ ]实现队列,int变量front存放队首元素的前一个元素的下标,rear存放队尾元素的下标,数组下标从0开始。
(1) 入队 push(x)
元素入队时,从队尾入队,需要先把rear+1,然后再把元素存放到rear指向的位置 (即+1后得新rear位置)。
void push(int x){
q[++rear] = x;
}
(2) 出队 pop()
从队首开始出。可以直接把队首指针+1实现出队。
void pop(){
front++;
}
(3) 取队首元素(get_front)
front指向队首的前一个元素,所以,front+1指向队首。
int get_front(){
return q[front+1];
}
(4) 取队尾元素(get_rear)
rear指向队尾元素,所以,直接访问rear即可。
int get_rear(){
return q[rear];
}
(5) 清空 clear()
使用数组来实现队列时,初始状态为front=-1,rear=-1,用此状态表示空队列。
void clear(){
front=rear=-1;
}
注意:真正的清空,是需要pop实现的,具体代码如下:
while(!q.empty()){
q.pop();
}
(6) 获取队列大小 size()
rear-front为队列的元素个数。
int size(){
return rear-front;
}
(7)判空 empty()
front==rear则为空,返回true;否则返回false。
bool empty(){
if(front==rear) return true;
else return false;
}
1.3 stack() 栈 后进先出
从栈顶加入,栈顶移除。
简单图示:
1.3.1 准备工作
#include< stack > ; using namespace std;
1.3.2 定义
stack< int > st;
1.3.3 直接使用
(1)进栈 push(x)
st.push(x) 将x压入栈,先放为栈底,后放为栈顶
(2)出栈 pop()
st.pop() 弹出栈顶元素。
(3)取栈顶元素 top()
st.top() 访问栈顶元素,不弹出。
(5)判空 empty()
st.empty();
(6)获取栈的大小 size()
st.size(); 返回值为int。
1.3.4 应用-非标准库
(1)进栈 push(x)
vi.push(x) 将x压入栈,先放为栈底,后放为栈顶
(2)出栈 pop()
vi.pop() 弹出栈顶元素
(3)取栈顶元素 top()
vi.top() 访问栈顶元素,不弹出
(5)判空 empty()
vi.empty(); bool类型的返回值,仅当TOP=-1时返回true,否则返回false。
(6)获取栈的大小 size()
栈内元素个数为TOP+1。
vi.size(); 返回值为int。
(4)清空 clear()
vi.clear() 栈的清空,实际是将栈顶指针置为-1,表示栈中没有元素。
TOP=-1;
注意:真正的清空,是需要pop实现的,具体代码如下:
while(!st.empty()){
st.pop();
}
1.4 链表处理
概念梳理:
链表和数组存储结构示意图:
1.4.1 为链表结点分配临时空间的两种方法
(1)C语言-malloc函数
头文件:#include<stdlib.h>
返回:申请的同变量类型的指针
用法:
//typename* p = (typename*)malloc(sizeof(typename));
int* p = (int*)malloc(sizeof(int));
node* p = (node*)malloc(sizeof(node));
(2)C++ new运算符
返回:申请的同变量类型的指针
用法:
//typename* p = new typename;
int* p = new int;
node* p = new node;
(3) 空间开辟后的释放-防止内存泄漏
① free函数-对应malloc函数
头文件:#include<stdlib.h>
用法:
free(p);//p为需要释放的内存空间的指针变量
实现效果:释放P指向的内存空间;将P指向空地址NULL。
② delete运算符-对应new运算符
用法:
delete(p);
1.4.2 链表的基本操作
map< string,int > mp; 字符串(键) 到 整型(值) 的映射,键是唯一的。
(1) 基本操作
创建链表: malloc或new创建结点后,只要把零散的结点连起来就形成链表了。方法是把每个结点的next指针指向下一个结点的地址即可。
建立链表代码:
#include<iostream>
#include <stdlib.h>
using namespace std;
//链表结点
struct node
{
int data;
node* next;
};
//创建链表
node* create(int Array[]) {
node *p, *pre, *head;//pre保存当前结点的前驱结点,head为头结点
head = new node;//创建头节点
head->next = NULL;//头节点不需要数据域,指针域为null
pre = head;//记录pre为head
for (int i = 0; i < 10; i++)//新建10个结点
{
p = new node;//新建节点
//将Array[i]赋值给新建的结点作为数据域,也可以cin输入
p->data = Array[i];
p->next = NULL;//新结点的指针域为NULL
pre->next = p;//前驱节点的指针域为当前新建节点的地址
pre = p;//把pre设为p,作为下个节点的前驱结点
}
return head;//返回头结点指针
}
int main()
{
int Array[10] = { 9,8,7,5,6,4,2,10,60,21 };
node* L = create(Array);//新建链表,返回头指针head赋值给L
L = L->next;//从第一个结点开始有数据域
while (L!=NULL)
{
cout << L->data << endl;
L = L->next;
}
system("pause");
return 0;
}
运行结果:
查询元素:
查询某个给定元素x,需要从第一个结点开始,不断地判断当前结点地数值域是否=x,若等于,给计数器count+1。这样到达结尾时,count=链表中元素x的个数。
查询代码:
//在以head为头结点的链表上计数x元素的个数
int search(node* head,int x){
int count = 0;
node* p=head->next;//从第一个节点开始
while(p!=NULL){//未到链表结尾
if(p->data == x) count++;
p=p->next;
}
return count;
}
插入元素:
在给定位置增加节点。
插入代码:
//将x插入以head为头结点的链表上的第pos位置
void insert(node* head,int pos,int x){
node* p=head;
for(int i=0;i<pos-1;i++){
p=p->next;//pos-1是为了到插入位置的前一个结点
}
node* q=new node;//新建结点
q->data=x;//新结点数据域x
q->next=p->next;//新结点的下一个结点指向原先位置的结点
p->next=q;//前一个位置的结点指向新结点
}
删除元素:
删除代码:
//市删除以head为头结点的链表上的所有以x为数据域的结点
void delete(node* head,int x){
node* p=head->next;//从第一个结点开始枚举
node* pre =head;//pre保存p的前驱结点的指针
while(p!=NULL){//未到链表结尾
if(p->data == x) {//需要删除的结点
pre->next=p->next;
delete(p);
p=pre->next;
}else{//不是要删除的结点,则把pre和p都后移一位
pre=p;
p->p->next;
}
}
}