设计题(11)

手撕vector

class myvector{
public:
    int cap = 99999;//数组的可用空间
    int num_size;
    int* vec = new int[cap];
    myvector(){
		this->num_size = 0;
    }
    ~myvector(){
    }
    void push_back(int val){
        if(num_size<cap)
            this->vec[num_size++] = val;
        //扩容
        else{
            this->cap = this->cap*2;
            int* new_vec = new int[this->cap];
            for(int i=0; i<num_size; i++){
                new_vec[i] = this->vec[i];
            }
            delete[] this->vec;
            this->vec = new_vec;
            this->vec[num_size++] = val;
        }
    }
    void pop_back(){
		if(num_size>0)
            this->num_size--;
        return -1;
    }
    int back(){
		if(num_size>0)
            return this->vec[num_size-1];
        return -1;
    }
}

手撕strcpy

需考虑内存重叠问题,复制前判断字符串是否包含

void strcpy1(char* a,const char* b)
{
    if (a == NULL || b == NULL)
        return;
    char* temp = a;
    int len = strlen(b)+ 1; 
    if (a > b && a < b + len){
        temp = temp + len - 1;
        b = b + len - 1;
        while (len--)
            *temp--=*b--;
    }
    else {
        while (len--)
            *temp++ = *b++;
    }
}

手撕string类

class MyString {
 public:
  MyString(const char* str = nullptr);         //普通构造函数
  MyString(const MyString& other);             //拷贝构造函数
  ~MyString(void);                             //析构函数
  MyString& operator=(const MyString& other);  //赋值函数
 private:
  char* m_data;  //用于保存字符串
};
//普通构造函数
MyString::MyString(const char* str) {
  if (str == nullptr) {
    m_data = new char[1];
    *m_data = '\0';
  } else {
    int length = strlen(str);
    m_data = new char[length + 1];
    strcpy(m_data, str);
  }
}
//析构函数
MyString::~MyString(void) {
  delete[] m_data;  //或delete m_data
}
//拷贝构造函数
MyString::MyString(const MyString& other)  //输入参数为const
{
  int length = strlen(other.m_data);
  m_data = new char[length + 1];
  strcpy(m_data, other.m_data);
}
//赋值函数
MyString& MyString::operator=(const MyString& other) {  //输入参数为const型
  if (this == &other) return *this;
  delete[] m_data;  //释放原有内存空间
  int length = strlen(other.m_data);
  m_data = new char[length + 1];
  strcpy(m_data, other.m_data);
  return *this;  //返回本对象应用
}

手撕shared_ptr

a、当创建智能指针类的新对象时,初始化指针,并将引用计数设置为1;
b、当能智能指针类对象作为另一个对象的副本时,拷贝构造函数复制副本的指向辅助类对象的指针,并增加辅助类对象对基础类对象的引用计数(加1);
c、使用赋值操作符对一个智能指针类对象进行赋值时,处理复杂一点:先使左操作数的引用计数减 1(为何减 1:因为指针已经指向别的地方),如果减1后引用计数为 0,则释放指针所指对象内存。然后增加右操作数所指对象的引用计数(为何增加:因为此时做操作数指向对象即右操作数指向对象);
d、完成析构函数:调用析构函数时,析构函数先使引用计数减 1,如果减至 0 则 delete 对象。

template<class T>
class SmartPtr{
public:
	SmartPtr(T* ptr = NULL): _ptr(ptr), _pcount(new int(1)) {} //构造函数
	SmartPtr(const SmartPtr& s): _ptr(s.ptr), _pcount(s._pcount){  //拷贝构造函数
		*(_pcount)++; //用指针进行count操作能够方便控制不同智能指针对象的计数值
	}
	SmartPtr<T>& operator=(const SmartPtr& s){  //重载 = ,赋值函数
		if(this != &s){ //检测自我赋值
			if(--(*(this->_pcount)) == 0){
				delete this->_ptr;
				delete this->_pcount;
			}
			_ptr = s._ptr;
			_pcount = s._pcount;
			*(_pcount)++;
		}
		return *this;
	}
	T& operator*(){
		return *(this->_ptr);
	}
	T* operator->(){
		return this->_ptr;
	}
	~SmartPtr(){ //析构函数要进行判定,count为0才会delete,delete之后避免野指针要赋值nullptr
		--(*(this->_pcount));
		if(this->_pcount == 0){
			delete _ptr;
			_ptr = nullptr;
			delete _pcount;
			_pcount = nullptr;
		}
	}
private:
	T* _ptr;
	int* _pcount;
};

手撕unique_ptr

class HasPtr{
	friend ostream& operator<<(ostream&, const HasPtr&);
public:
	//构造函数 
	HasPtr(const string &s = string()):ps(new string(s))
		{cout<< "HasPtr(const string &s = string())"<<endl;}	
	
	HasPtr(HasPtr&& rhs) noexcept :ps(rhs.ps){rhs.ps = nullptr; cout<< "HasPtr(HasPtr&&)"<<endl;}
		
	//拷贝构造函数   
	HasPtr& operator=(HasPtr &&p){
				if(this != &rhs){
				if(ps)
					delete ps;
				ps  = rhs.ps;
				rhs.ps = nullptr;
			}
	}
	
	HasPtr(const HasPtr&) = delete;			//拷贝构造与赋值不能使用 
	HasPtr& operator=(const HasPtr&) = delete;
	
	//析构函数 
	~HasPtr(){
		if(ps)
			delete ps;
	};
private:	
	string *ps;
};

手撕单例模式

懒汉式(懒汉式原来会有安全问题,c++11解决了多线程安全问题)

class CSingleton
{
private:
	CSingleton(){ cout << "单例对象创建!" << endl; };
	CSingleton(const CSingleton &);
	CSingleton& operator=(const CSingleton &);
	~CSingleton(){ cout << "单例对象销毁!" << endl; };
public:
	static CSingleton * getInstance()
	{	
		static CSingleton myInstance;
		return &myInstance;
	}
};

饿汉式

class CSingleton
{
private:
	CSingleton(){ cout << "单例对象创建!" << endl; };
	CSingleton(const CSingleton &);
	CSingleton& operator=(const CSingleton &);
	~CSingleton(){ cout << "单例对象销毁!" << endl; };
 
	static CSingleton myInstance; // 单例对象在这里!
public:
	static CSingleton* getInstance()
	{		
		return &myInstance;
	}
};

手撕生产者消费者

#define PRODUCER_NUM 5 //生产者数目
#define CONSUMER_NUM 5 //消费者数目
#define POOL_SIZE	 11  //缓冲池大小
int pool[POOL_SIZE];	//缓冲区
int head=0;	//缓冲池读取指针
int rear=0; //缓冲池写入指针
sem_t	room_sem;		//同步信号信号量,表示缓冲区有可用空间
sem_t	product_sem;		//同步信号量,表示缓冲区有可用产品
pthread_mutex_t mutex;
void producer_fun(void *arg)
{
	while (1)
	{
		sleep(1);
		sem_wait(&room_sem);
		pthread_mutex_lock(&mutex);
		//生产者往缓冲池中写入数据
		pool[rear] = 1;
		rear = (rear + 1) % POOL_SIZE;
		printf("producer %d write to pool\n", (int)arg);
		printf("pool size is %d\n",(rear-head+POOL_SIZE)%POOL_SIZE);
		pthread_mutex_unlock(&mutex);
		sem_post(&product_sem);
	}
} 
void consumer_fun(void *arg)
{
	while (1)
	{
		int data;
		sleep(10);
		sem_wait(&product_sem);
		pthread_mutex_lock(&mutex);
		//消费者从缓冲池读取数据
		data = pool[head];
		head = (head + 1) % POOL_SIZE;
		printf("consumer %d read from pool\n", (int)arg);
		printf("pool size is %d\n",(rear-head+POOL_SIZE)%POOL_SIZE);
		pthread_mutex_unlock(&mutex);
		sem_post(&room_sem);
	}
} 
int main()
{
	pthread_t producer_id[PRODUCER_NUM];
	pthread_t consumer_id[CONSUMER_NUM];
	pthread_mutex_init(&mutex, NULL);	//初始化互斥量
	int ret = sem_init(&room_sem, 0, POOL_SIZE-1);	//初始化信号量room_sem为缓冲池大小
	ret = sem_init(&product_sem, 0, 0);	//初始化信号量product_sem为0,开始时缓冲池中没有数据
	for (int i = 0; i < PRODUCER_NUM; i++)
	{
		//创建生产者线程
		ret =pthread_create(&producer_id[i], NULL, producer_fun, (void*)i);
		//创建消费者线程
		ret = pthread_create(&consumer_id[i], NULL, consumer_fun, (void*)i);
	}
}

手撕读写锁

在这里插入图片描述

手撕线程安全的队列

template<typename T> class ThreadSafe_Queue
{
private:
    mutable mutex m_mut;
    queue<T> m_queue;
    condition_variable m_data_cond;
public:
    ThreadSafe_Queue() {}
    ThreadSafe_Queue(const ThreadSafe_Queue&) = delete;
    void push(T data)
    {
        lock_guard<mutex> lg(m_mut);
        m_queue.push(data);
        m_data_cond.notify_one();
    }
    void WaitPop(T&t)
    {
        unique_lock<mutex> ul(m_mut);
        m_data_cond.wait(ul, [this] {return !m_queue.empty(); });
        t = m_queue.front();
        m_queue.pop();
    }
    bool TryPop(T &t)
    {
        lock_guard<mutex> lg(m_mut);
        if (m_queue.empty())
            return false;

        t = m_queue.front();
        m_queue.pop();
        return true;
    }
    bool IsEmpty()
    {
        lock_guard<mutex> lg(m_mut);
        return m_queue.empty();
    }
};

手撕bitsetbitset接口

struct Bitset
{
	unsigned a[1600];
	void reset(){
		memset(a,0,sizeof(a));
	}
	Bitset(){
		reset();
	}
	void flip(int x){
		a[x>>5]^=1<<(x&31);
	}
	void set(int x){
		a[x>>5]|=1<<(x&31);
	}
	void reset(int x){
		a[x>>5]&=~(1<<(x&31));
	}
	int test(int x){
		return (a[x>>5]>>(x&31))&1;
	}
	Bitset operator ~()const{
		Bitset ret;
		for(int i=0;i<1600;i++)ret.a[i]=~a[i];
		return ret;
	}
	Bitset operator &(const Bitset &b)const{
		Bitset ret;
		for(int i=0;i<1600;i++)ret.a[i]=a[i]&b.a[i];
		return ret;
	}
	Bitset operator |(const Bitset &b)const{
		Bitset ret;
		for(int i=0;i<1600;i++)ret.a[i]=a[i]|b.a[i];
		return ret;
	}
	Bitset operator ^(const Bitset &b)const{
		Bitset ret;
		for(int i=0;i<1600;i++)ret.a[i]=a[i]^b.a[i];
		return ret;
	}
	Bitset operator <<(const int t)const{
		Bitset ret;
		unsigned last=0;
		int high=t>>5,low=t&31;
		for(int i=0;i+high<1600;i++){
			ret.a[i+high]=last|(a[i]<<low);
			if(low)last=a[i]>>(32-low);
		}
		return ret;
	}
	Bitset operator >>(const int t)const{
		Bitset ret;
		unsigned last=0;
		int high=t>>5,low=t&31;
		for(int i=1600-1;i>=high;i--){
			ret.a[i-high]=last|(a[i]>>low);
			if(low)last=a[i]<<(32-low);
		}
		return ret;
	}
	vector<int> ones()const{
		vector<int> ret;
		for(int i=0;i<1600;i++){
			unsigned tmp=a[i];
			while(tmp){
				short t=__builtin_ctz(tmp);
				ret.pb((i<<5)|t);
				tmp^=1u<<t;
			}
		}
		return ret;
	}
}use,trans,cur;

手撕布隆过滤器

class BloomFilterDemo {
    //设置的位集大小
    private int defaultSize = 16 << 24;
    //最大索引位置
    private int maxIndex = defaultSize - 1;
    //建立一个二进制位集
    private BitSet bits = new BitSet(defaultSize);
    /*** 添加元素的方法*/
    public void add(String key) {
        int bloomCode[] = getCode(key);
        for (int i = 0; i < 8; i++) {
            bits.set(bloomCode[i]); // 这里影响添加的元素大小
        }
    }
    /** 随机数生成器 */
    private int[] getCode(String key) {
        int[] randomArr = new int[8];
        for (int i = 0; i < 8; i++) {
            randomArr[i] = hash(key, i);
        }
        return randomArr;
    }
    /*** 自己定义的hash算法(一定要用&运算)
     * @param key 输入的key值
     * @param n   自定义的参数,用来传入不同参数生成不同的随机数*/
    private int hash(String key, int n) {
        int result = key.hashCode() * n;
        return result & maxIndex;
    }
    /** 判断一个元素是否在表中*/
    public boolean exits(String key) {
        int keyCode[] = getCode(key);
        if (bits.get(keyCode[0]) && bits.get(keyCode[1])
                && bits.get(keyCode[2]) && bits.get(keyCode[3])
                && bits.get(keyCode[4]) && bits.get(keyCode[5])
                && bits.get(keyCode[6]) && bits.get(keyCode[7])) {
            return true;
        }
        return false;
    }
}
public class BloomFilter {
    public static void main(String[] args) {
        BloomFilterDemo bf = new BloomFilterDemo();
        Long aBeginTime = System.currentTimeMillis();// 记录BeginTime
        for (int i = 0; i < 100000; i++) {
            bf.add("Java" + i);
        }
        Long aEndTime = System.currentTimeMillis();// 记录EndTime
        System.out.println("Insert Time-->" + (aEndTime - aBeginTime));
        Long lBeginTime = System.currentTimeMillis();// 记录BeginTime
        System.out.println(bf.exits("Java" + 99139));
        Long lEndTime = System.currentTimeMillis();// 记录EndTime
        System.out.println("Search Time--->" + (lEndTime - lBeginTime));
    }
}

355. 设计推特

对于操作 3 和操作 4,我们只需要用一个哈希表存储,即可实现插入和删除的时间复杂度都为 O(1)O(1)。

对于操作 1 和操作 2,由于操作 2 要知道此用户关注的人和用户自己发出的最近十条推文,因此我们可以考虑对每个用户用链表存储发送的推文。每次创建推文的时候我们在链表头插入,这样能保证链表里存储的推文的时间是从最近到最久的。那么对于操作 2,问题其实就等价于有若干个有序的链表,我们需要找到它们合起来最近的十条推文。由于链表里存储的数据都是有序的,所以我们将这些链表进行线性归并即可得到最近的十条推文。这个操作与 23. 合并K个排序链表 基本等同。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值