今天讲讲基本数据结构部分啊,比较难理解,多看几遍好多了,能看懂,但不会写。
本来想把基本数据结构打完,看来是我想多了。。。
-
链表
~链表,就是像铁链一样一节连一节,每节都有自己的value和next,代码如下:
struct node {int value,next;}a[MAX];
int insert(int p,int q)//把q元素插到第p个元素后
{
top++;//链表中元素个数
a[top].value=q;
a[top].next=a[p].next;
a[p].next=top;
}
//以下是遍历
int temp=head;
while(temp)
{
cout<<a[temp].value;
temp=a[temp].next;//查找下一个
}
~循环链表 与单链表的区别就是最后一个元素的next指向head
~双向链表 差别不大 就是每个元素不仅有next还有prev(前驱后继)
举个例子更好理解
例: 将元素p插入升序链表中
void insert(int p)
{
int now,last;
a[++top].value=p;
if(a[head].value>p)//
{
a[top].next=head;
a[head].prev=top;
head=top;
}
else
{
now=head;
while()(a[now].value<p)&&(now<top))
{
last=now;
now=a[now].next;
}
a[last].next=top;
a[top].prev=last;
a[top].next=now;
a[now].prev=top;
}
}
-
栈 (先进后出)
stl库中有栈这个容器,但是一般自己实现(一般情况下,调用栈的空间大小为16MB)
int stck[maxx],top=0;//栈顶位置
void push(int a){stack[++top]=a;}//入栈
int pop(){return stack[--top];}//出栈并返回栈顶
bool empty(){return top<1;}//栈是否为空
使用栈模拟递归时,注意入栈顺序 -->逆序入栈,先递归的后入栈
-
队列(先进后出)
int a[maxx],head=0,tail=0;//首个元素 尾部元素
void push(int a)
{
a[++tail]=a;
}
int pop()
{
return a[head++];
}
bool empty()
{
return head>tail;
}
~循环队列 相对以上链状队列节省很大空间
int a[N],head=1,tail=1;
void push(int a)
{
a[tail]=a;
tail=(tail+1)%N;
}
int pop()
{
int t=a[head];
head=(head+1)%N;
return t;
}
bool empty()//队空或队满的条件
{
return head==tail;
}
此处empty有必要说一下
区别队空队满的方法个人觉得比较好理解的一种:
在进出队时记录元素个数,这样直接检查元素个数就能判断了;
~单调队列
表示没搞懂单调队列和一般队列的特殊区别,感觉没差多少
4.树和二叉树
对于树的概念就不多说了,自行查提高篇P77;
~二叉树的链表存储法
struct node
{
int value;
int leftchild,rightchild;
int id; //结点编号
int parent; //指向父结点
}a[N];
int top=0,head=0;
#define NEM(p) p=&a[++top]; //懒人用的宏定义
p.leftchild=__;
p.rightchild=__;
p.value=__;
~完全二叉树的一维数组存储法(找度娘)
~二叉树的遍历(我们默认二叉树左子树的优先级高于右子数)
其实三种遍历的代码差不多
1)前序遍历
void preorder(int p)
{
if(p==0) return;//处理结点p
cout<<a[p].value;
preorder(a[p].leftchild);
preorder(a[p].rughtchild);
}
2)中序遍历
void inorder(int p)
{
if(p==0) return;
inorder(a[p].leftchild);
cout<<a[p].value;
inorder(a[p].rightchild);
}
3)后续遍历
void postorder(int p)
{
if(p==0) return;
postorder(a[p].leftchild);
cout<<a[p].value;
postorder(a[p].rightchild);
}
~二叉树重建
1)输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
上代码:
void postorder(int n,int la,int lb)
{
if(n<=0) return;
for(int i=la;i<=la+n-1;i++)
if(a[i]==b[lb])
{
postorder(i-la,la,lb+1);
postorder(la+n-1-i,i+1,lb+i-la+1);
cout<<b[lb];
return;
}
}
2)给出 后序遍历 中序遍历 求前序遍历
其实道理差不多
void postorder(int n,int la,int lb)
{
if(n<=0) return;
for(int i=la;i<=la+n-1;i++)
if(a[i]==b[lb])
{
cout<<b[lb];//此处较上文 位置改变
postorder(i-la,la,lb+1);
postorder(la+n-1-i,i+1,lb+i-la+1);
return;
}
}
3) 求中序 (有多组解)
~ 求二叉树的直径 (暂时不懂,P80页)
5.并查集
struct node
{
int parent,value;
} set[MAX];
int getfather(int x)//递归版本(数据太大会爆栈)
{
if(set[x].father==x) return x;
else
{
set[x].parent=getfather(set[x].parent);
return set[x].parent;
}
//下面是问号表达式的写法,更简洁
//return (set[x].parent==x)? x:(set[x].parent=getfather(set[x].parent));
}
int getfather(int x)//非递归版本
{
int y=x;
while(set[y].parent!=y) //寻找父结点
y=set[y].parent;
while(x!=y) //路径压缩,把途中经过的结点的父亲都改为y
{
int tmp=set[x].parent;
set[x].parent=y;
x=tmp;
}
return y;
}
void Union(int x,int y) //小写union是关键词
{
x=getfather(x);y=getfather(y); //寻找各自根节点
if(x==y) return;
set[y].parent=x; //若不在同个集合,合并
}
void init(int cnt) //初始化并查集,cnt为元素个数
{
for(int i=1;i<=cnt;i++)
{
set[i].parent=i;
set[i].value=0;
}
}
-----------------------------------华丽分割线--------------------------------
打了三个半小时,发现自己之前漏了好多知识点
总结真的有用,嗯!