复习总结,代码及基本内容来源:
《算法笔记》
《算法竞赛入门经典》
排序
- 稳定排序和不稳定排序
在简单形式化一下,如果Ai = Aj,Ai原来在位置前,排序后Ai还是要在Aj位置前。
选择排序、快速排序是不稳定排序(STL 方法sort)。冒泡排序、插入排序是稳定排序(STL方法 stable_sort)。
冒泡排序(稳定排序)
void Bubblesort(int a[],int n){
int i,j,temp;
for(int i=0;ia[j+1]){
swap(a[j],a[j+1]);
}
}
}
}
插入排序的思想(稳定)
插入排序的思想 将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中
比如将a[i] , 插入a[0:i-1]中
int A[maxn],n;
void insertSort(){
for(int i=2;i<=n;i++){
int temp=A[i],j=i;
while(j>1 && temp
选择排序(不稳定排序)
其它
归并排序(稳定)O(n logn)
快速排序(不稳定)比较好:O(n logn) 比较不好:O(n^2)
一般一个在最左,一个在最右,最左找小于基准,最右找大于基准,然后交换。
然后左边的找基准,重复进行;然后右边的找基准,重复进行。(可以用递归)
堆
向上调整方法,向下调整方法
完全树,左孩子2i位,右孩子2i+1位
const int maxn=100;//
int heap[maxn],n=10;
//n,一共多少个元素
void downAdjust(int low,int high){//最大堆,
int i=low,j=i*2;//i为欲调整节点,j为其左孩子
while(j<=high){//就是没有到最后
if(j+1<=high&&heap[j+1]>heap[j]){//右孩子存在且值大于左孩子
j=j+1;
}
if(heap[j]>heap[i]){
swap(heap[j],heap[i]);//交换函数
i=j;
j=i/2
}else{
break;//调整结束
}
}
}
void createHeap(){
for(int i=n/2;i>=1;i--){
downAdjust(i,n);
}
}
void deletetop(){
heap[1]=heap[n--]://用最后一个元素覆盖堆顶元素
downAdjust(1,n);//向下调整堆顶元素
}
//添加堆顶元素,向上调整
void upAdjust(int low,int high){
int i=high,j=i/2;
while(j>=low){
if(heap[j]
二叉树
二叉树静态结构
数组:给定一课包含(d为二叉树高度)的完全二叉树,如果把节点从上到下从左到右的编号为1,2,3,……则结点k的左右子节点编号分别为2k和2k+1。
二叉树动态结构
根据需要建立新的结点,然后将其组织成一颗树。
char s[maxn];
bool read_input(){
failed=false;
root=newnode();
for(;;){
if(scanf("%s",s)!=1) return false;//输入结束
if(!strcmp(s,"()")) break;//读到结束标志,退出循环
int v;
sscanf(&s[1],"%d",&v);
addnode(v,strchr(s,',')+1);//查找逗号,再插入结点。
}
return true;
}
\\二叉树结点和定义
struct Node{
bool have_value;//初始false
int v;
Node *left,*right;//(NULL),注意这里用的也是指针
//可以写一下初始化函数什么的
public:
void init(Node* left,int length,int id){//初始化方法
this->next=next;
this->weight=length;
}
}
Node *root;//跟结点
-----------------------------------------
node *newnode=new node();//新建节点,用的是指针
newnode->init(1,b);
current->next=newnode;
--------------------------------------------------
Node* newnode(){
Node x= new Node();
x.init();
return x;//不知道可不可以
}
由于二叉树是递归定义的,其左右子节点类型都是指向结点类型的指针。因此结点类型为Node,其左右子节点类型是Node*
void addnode(int v,char* s){
int n=strlen(s);
Node* u=root;//根节点开始定义好了
for(int i=0;ileft == NULL){
node *newnode=new node();//新建节点,用的是指针
newnode->init(1,b);
u->left=newnode;
}
u=u->left;
}else if(s[i]=='R'){
if(u->right==NULL) u->right=newnode();
u=u->right;
}
if(u->have_value) failed=true;//赋过值,表明输入有误
u->v=v;
u->have_value=true;//别忘记做标记。
}
}
//层次遍历,这里使用bfs
bool bfs(vector& ans){//注意这里是引用!!!
queue q;//队列装的是node指针
ans.clear();//清空!!!
q.push(root);
while(!q.empty()){
Node* u=q.front();
if(!u->have_value) return false;//输入有误
ans.push_back(u->v);
if(u->left!=NULL) q.push(u->left);
if(u->right!=NULL) q.push(u->right);
}
return true;
}
数组实现
主要note:多个属性就是多个数组
接下来,把所有的Node类型改成int类型,然后把结点结构中的成员变量改成全局数组
(例如,u->left和u->right分别改成left[u]和right[u]),除了char外,整个程序就没有任何指
针了。
二叉树的递归遍历
对于二叉树T,可以递归定义它的先序遍历、中序遍历和后序遍历,PreOrder(T)=T的根节点+preOrder(T的左子树)+PreOrder(T的右子树)
InOrder(T)=InOder(T的左子树)+T的根节点+InOrder(T的右子树)
PostOrder(T)=PostOrder(T的左子树)+Postorder(T的右子树)+T的根节点。
前序遍历
void preorder(node* root){
if(root == NULL){
return;//到达空树,递归边界
}
//访问根节点root,例如将其数据域输出
printf("%d\n",root->data);
//访问左子树
preorder(root->lchild);//左子树
preorder(root->rchild);//右子树
}
中序遍历
void inorder(node* root){
if(root == NULL){
return;//到达空树,递归边界
}
//访问根节点root,例如将其数据域输出
inorder(root->lchild);//左子树
printf("%d\n",root->data);
//访问左子树
inorder(root->rchild);//右子树
}
给定前序和中序得到二叉树
需要在中序序列中找到某个节点,使得,即最主要的是找到对应的子树的前序和中序,然后就能不停地遍历了。左子树的节点个数:k-1。左子树的先序序列区间[2,k],左子树中序序列区间[1,k-1],右子树的先序序列区间和中序序列区间都是[k+1,n]。
node* create(int preL,int preR,int inL,int inR){//注意这里返回的是指针
if(preL>preR){
return NULL;//先序序列长度小于等于0时,直接返回
}
node* root = new node();
root->data=pre[preL];//前序开头是根节点
int k;
for(k=inL;k<=inR;k++){
if(in[k]==pre[preL]){
//在中序序列中找到in[k]==pre[L]的节点
break;
}
}
int numLeft=k-inL;//左子树的节点个数
//则可知,左子树先序[preL+1,preL+numLeft],中序区间[inL,k-1]
//返回左子树的根节点地址,赋值给root的左指针
root->lchild=create(preL+1,preL+numLeft,inL,k-1);
//右子树的先序区间为preL+numberLeft+1,preR],中序区间为[k+1,inR]
root->rchild=create(preL+numLeft+1,preR,k+1,inR);
return root;//返回根节点地址
}
给定后序序列和中序序列,如何构建二叉树
后序与前序的不同,notice,后序序列最后一个元素为根元素,所以倒着找就可以了,找到中序中的根元素,找到左右子区间
给定二叉树的中序遍历和后序遍历,可以构造出这棵二叉树。
#include
#include
#include
#include
using namespce std;
//因为各个结点的权值各不相同且都是正整数,直接用权值作为结点编号。
const int maxv=10000 + 10;
int in_order[maxv],post_order[maxv],lch[maxv],rch[maxv];
int n;
bool read_list(int *a){
string line;
if(!getline(cin,line)) return false;
stringstream ss(line);
n=0;
int x;
while(ss>>x) a[n++]=x;
return n>0;
}
int build(int L1,int R1,int L2,int R2){
if(L1>R1) return 0;//空树
int root =post_order[R2];
int p=L1;
while(in_order[p]!=root) p++;
int cnt=p-L1;//左子树结点个数
lch[root]=built(L1,p-1,L2,L2+cnt-1);
rch[root]=built(p+1,R1,L2+cnt,R2-1);
return root;
}
int best, best_sum; //目前为止的最优解和对应的权和
void dfs(int u, int sum) {
sum += u;
if(!lch[u] && !rch[u]) { //叶子
if(sum < best_sum || (sum == best_sum && u < best)) { best = u; best_sum
= sum; }
}
if(lch[u]) dfs(lch[u], sum);
if(rch[u]) dfs(rch[u], sum);
}
int main() {
while(read_list(in_order)) {
read_list(post_order);
build(0, n-1, 0, n-1);
best_sum = 1000000000;
dfs(post_order[n-1], 0);
cout << best << "\n";
}
return 0;
}