是两个手写数据结构的题,所以想着记录一下,说不定以后哪天就用上了(可能不会)
另外3.30的第三问怎么证明啊,有无会的大佬教一下,呜呜。
3.28 实现双端队列
/* 本双端队列中:
1.[head,rear-1]范围内存元素
2.特殊地,head==rear时为空,head==(rear+1)%size时为满
3.为了满足2的要求,数组中留空一个位置,size大小的数组只能存size-1个元素
*/
template<class T>
class Deque{
private:
vector<T> dq;
int head, rear, size;
public:
Deque(int n){
size=n+1;
head=rear=0;
dq=vector<T>(n+1);
}
bool isFull(){ //检查是否为满
return head==(rear+1)%size;
}
bool isEmpty(){ //检查是否为空
return head==rear;
}
bool push(T x){ //插入前端
if(isFull()) return false; //已满,添加失败
head = (head-1+size)%size;
dq[head]=x;
return true;
}
T pop(){ //删除前端并返回
if(isEmpty()) return -1; //已空,删除失败
int pre=head;
head = (head+1)%size;
return dq[pre];
}
bool inject(T x){ //插入后端
if(isFull()) return false;
dq[rear]=x;
rear=(rear+1)%size;
return true;
}
bool eject(){ //删除后端并返回
if(isEmpty()) return -1;
rear=(rear-1+size)%size;
return dq[rear];
}
};
3.30 实现自调整表(数组实现+链表实现)
/* 基于数组实现的自调整表
1.[0,cnt-1]范围内存储元素
2.插入操作和find操作都是O(N)的复杂度
*/
template<class T>
class Self_Adjust_List{
private:
vector<T> sal;
int size, cnt;
public:
Self_Adjust_List(int n){
sal=vector<T>(n);
size=n, cnt=0;
}
bool isFull(){
return cnt==size;
}
bool isEmpty(){
return cnt==0;
}
bool insert(T x){
if(isFull()) return false; //满了,插入失败
for(int i=cnt-1; i>=0; i--){
sal[i+1]=sal[i];
}
sal[0]=x, cnt++;
return true;
}
bool find(T x){
int pos=-1;
for(int i=0; i<=cnt-1; i++){
if(sal[i]==x) {pos=i; break;}
}
if(pos==-1) return false; //没找到元素x
for(int i=pos-1; i>=0; i--){
sal[i+1]=sal[i];
}
sal[0]=x;
return true;
}
void printTop(){
cout<<sal[0]<<endl;
}
};
/* 链表结点的结构体实现(用来实现后面的自调整表的链表实现)
使用方法:node<int> *head = new node<int>(); head->val=1;
*/
template <class T>
struct node{
node* nxt;
T val;
node(){nxt=nullptr; val=0;}
node(T x){nxt=nullptr; val=x;}
};
/* 自调整表的链表实现
1.由于是链表实现,不再设空间限制
2.插入操作是O(1),find操作是O(N)
3.但如果每个元素都有固定的访问概率pi,那么访问概率高的将更容易排在表的前面,
这使得find操作的均摊复杂度要优于线性复杂度
4.上述分析的证明我也不会,呜呜
*/
template <class T>
class Self_Adjust_List2{
private:
int size;
node<T> *head;
public:
Self_Adjust_List2(){
size=0;
head = new node<T>();
}
//以下是两个实现所需的链表函数
void addAtHead(T x){ //把元素加到链表头
node<T> *cur = new node<T>(x);
cur->nxt = head->nxt;
head->nxt = cur;
size++;
}
void deleteNext(node<T> *cur){ //把当前指针的nxt指向的元素删掉
node<T> *toDel = cur->nxt; //将要删掉的元素的指针
if(toDel==nullptr) return; //如果是空的,就不用删了
cur->nxt = toDel->nxt;
delete toDel;
size--;
}
//以下是两个自调整表的函数
void insert(T x){
addAtHead(x);
}
bool find(T x){
node<T> *cur=head; //设置一个指针从head开始遍历链表
for(; ; cur=cur->nxt){ //遍历链表
if(cur->nxt==nullptr) return false; //没找到元素x
if(cur->nxt->val==x) break; //找到目标元素,进入下一步
}
//删除然后在前端加,相当于移到前端
deleteNext(cur);
addAtHead(x);
return true;
}
};