面试题——各种功能函数实现(一)

面试题——各种功能函数实现(三)

实现自己的memcpy

void *my_memcpy(void *dest, void *src, int num){
	assert(dest != NULL && src != NULL);
	char *pdest = (char *)dest;
	char *psrc = (char *)src;
	while(num--){
		*pdest = *psrc;
		pdest++;
		psrc++;
	}
	return dest;
}

实现LRU缓存机制
这个思路是维护一个hash用来快速查找,维护一个双向链表使得有序,新访问的元素放前面,若满了,pop_back删除最后元素

class LRUCache {
    list<pair<int, int>> cache;
    unordered_map<int, list<pair<int, int>>::iterator> map;
    int cap;
public:
    LRUCache(int capacity) {
        cap = capacity;
    }

    int get(int key) {
        if (map.count(key) > 0){
            //注意,这里一定要得到实体temp,而不是迭代器temp,因为后面erase会丢失
            auto temp = *map[key];
            cache.erase(map[key]);
            map.erase(key);
            cache.push_front(temp);
            map[key] = cache.begin();
            return temp.second;
        }
        return -1;
    }
    
    void put(int key, int value) {
        if (map.count(key) > 0){
            cache.erase(map[key]);
            map.erase(key);
        }
        else if (cap == cache.size()){
            auto temp = cache.back();
            cache.pop_back();
            map.erase(temp.first);
        }
        cache.push_front(pair<int, int>(key, value));
        map[key] = cache.begin();
    }
};
/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

实现平衡树旋转

#include 
using namespace std;
struct node {
    int val;
    struct node *left, *right;
};
node *rotateLeft(node *root) {
    node *t = root->right;
    root->right = t->left;
    t->left = root;
    return t;
}
node *rotateRight(node *root) {
    node *t = root->left;
    root->left = t->right;
    t->right = root;
    return t;
}
node *rotateLeftRight(node *root) {
    root->left = rotateLeft(root->left);
    return rotateRight(root);
}
node *rotateRightLeft(node *root) {
    root->right = rotateRight(root->right);
    return rotateLeft(root);
}
int getHeight(node *root) {
    if(root == NULL) return 0;
    return max(getHeight(root->left), getHeight(root->right)) + 1;
}
node *insert(node *root, int val) {
    if(root == NULL) {
        root = new node();
        root->val = val;
        root->left = root->right = NULL;
    } else if(val < root->val) {
        root->left = insert(root->left, val);
        if(getHeight(root->left) - getHeight(root->right) == 2)
            root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root);
    } else {
        root->right = insert(root->right, val);
        if(getHeight(root->left) - getHeight(root->right) == -2)
            root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root);
    }
    return root;
}
int main() {
    int n, val;
    scanf("%d", &n);
    node *root = NULL;
    for(int i = 0; i < n; i++) {
        scanf("%d", &val);
        root = insert(root, val);
    }
    printf("%d", root->val);
    return 0;
}

实现一个多态

#include  
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0){
         width = a;
         height = b;
      }
      virtual int area(){
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      int area (){ 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      int area (){ 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};
// 程序的主函数
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);
 
   // 存储矩形的地址
   shape = &rec;
   // 调用矩形的求面积函数 area
   shape->area();
 
   // 存储三角形的地址
   shape = &tri;
   // 调用三角形的求面积函数 area
   shape->area();
   //此时父类指针有了多种形态,这就是多态的本质
   return 0;
}
//下面是输出结果
//Rectangle class area
//Triangle class area

多线程与互斥锁简单实例

#include
#include 
#include 
#include 
using namespace std;

int number1 = 0;
int number2 = 0;
int sum = 0;
mutex g_lock;

int ThreadProc1(){
	g_lock.lock();
    number1 = rand() % 10;
    g_lock.unlock();
    this_thread::sleep_for(chrono::milliseconds(10));
    return 0;
}

int ThreadProc2(){
	g_lock.lock();
    number2 = rand() % 10;
    g_lock.unlock();
    this_thread::sleep_for(chrono::milliseconds(10));
    return 0;
}

int ThreadProc2(){
	g_lock.lock();
    sum = number1 + number2;
    g_lock.unlock();
    this_thread::sleep_for(chrono::milliseconds(10));
    return 0;
}

int main()
{
    thread t1(ThreadProc1);
    thread t2(ThreadProc2);
    thread t3(ThreadProc2);

    t1.join();//阻塞直到线程执行完成
    t2.join();
    t3.join();

    system("pause");
    return 0;
}

//如果不想阻塞在这里就将join()换成使用线程的detach()方法,将线程与线程对象分离,线程就可以继续运行下去,并且不会造成影响。

生产者消费者模型简单实现
原理
存储的数据的区域可以用一个队列来模拟,然后我们通过C++11提供的条件变量来通知写入线程在数据不满的时候进行写入,在数据满的时候挂起,对读取线程也是同理。

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
std::mutex g_mtxDeque;
std::mutex g_mtxCout;
std::condition_variable g_cv_not_empty;
std::condition_variable g_cv_not_full;
std::deque<int> g_deque;
int g_itemIndex = 0;

const int g_kItemSize = 30;//产品个数
const int g_kDequeSize = 10;//队列大小

void produceItem()
{
	this_thread::sleep_for(chrono::seconds(1));
	unique_lock<mutex> lock(g_mtxDeque);//队列加锁
	g_cv_not_full.wait(lock, []() { return g_deque.size() < g_kDequeSize; });//直到队列满,此时wait就阻塞在这里

	++g_itemIndex;
	g_deque.push_back(g_itemIndex);
	{
		lock_guard<mutex> lock_guard(g_mtxCout);
		cout << "produce item " << g_itemIndex << endl;
	}
	lock.unlock();
	g_cv_not_empty.notify_all();//通知线程
}

void consumeItem()
{
	this_thread::sleep_for(chrono::seconds(2));
	unique_lock<mutex> lock(g_mtxDeque);
	g_cv_not_empty.wait(lock, []() { return !g_deque.empty(); });//队列为空只,此时wait将阻塞在这里

	int itemIndex = g_deque.front();
	g_deque.pop_front();
	{
		lock_guard<mutex> lock_guard(g_mtxCout);
		cout << "consume item " << itemIndex << endl;
	}
	lock.unlock();
	g_cv_not_full.notify_one();
}

void produceTask()
{
	int count = g_kItemSize;
	while (count--){
		produceItem();
	}
}

void consumeTask()
{
	int count = g_kItemSize;
	while (count--){
		consumeItem();
	}
}

//单生产者单消费者模型
void consumeProduceTest(){
	std::vector<std::thread> threads;
	thread thread1(produceTask);
	thread thread1(consumeTask);
	thread1.join();
	thread2.join();
}

string类的实现

class my_string
{
public:
	my_string(char *str == nullptr);
	~my_string();
	my_string(const my_string& other);
	my_string& operator=(const my_string& other);	
private:
	char *m_data;	
};

my_string::my_string(char *str){
	if (str == nullptr){
		m_data = new char[1];
		m_data = '\0';
	}
	else{
		int len = strlen(str);
		m_data = new char[len+1];
		strcpy(m_data, str);
	}
}

my_string::my_string(const my_string& other){
	int len = strlen(other.m_data);
	m_data = new char[len+1];
	strcpy(m_data, other.m_data);
}

my_string& my_string::operator=(const my_string& other){
	if (this == &other)
		return *this;
	delete[] m_data;
	int len = strlen(other.m_data);
	m_data = new char[len+1];
	strcpy(m_data, other.m_data);
	return *this;
}

my_string::~my_string(){
	if (m_data != nullptr){
		delete[] m_data;
		m_data = nullptr;
	}
}

抢红包算法
两倍均值法

#include 
using namespace std;
int main(){
    double money;
    while (cin >> money){
        int n = 10;
        for (int i=0; i<n; i++){
            double max = money / n * 2;//区间
            double randval = rand() / double(RAND_MAX);//生成0-1的浮点数
            cout << randval * max << endl;
            money -= randval * max;
        }
    }
    return 0;
}

另一种方法是先为每个人分配0.01元,然后开始随机抽取一个红包增加0.01元,直到总金额为0
真正随机的是第三种方法,线段法:
1、如何确定每一条子线段的长度呢?由“切割点”来决定。当N个人一起抢红包的时候,就需要确定N-1个切割点。
2、因此,当N个人一起抢总金额为M的红包时,我们需要做N-1次随机运算,以此确定N-1个切割点。随机的范围区间是(1, M)。
3、当所有切割点确定以后,子线段的长度也随之确定。这样每个人来抢红包的时候,只需要顺次领取与子线段长度等价的红包金额即可。

#include 
using namespace std;
int main(){
    double money;
    while (cin >> money){
        int n = 10;
        vector<double> arr(n-1, 0.01);
        for (int i=0; i<n-1; i++){
            arr[i] += rand() / double(RAND_MAX) * (money-0.1);//生成0-1的浮点数
        }
        sort(arr.begin(), arr.end());
        cout << arr[0] << endl;
        for (int i=1; i<n-1; i++)
            cout << arr[i]-arr[i-1] << endl;
        cout << money-arr[arr.size()-1] << endl;
    }
    return 0;
}

洗牌算法

#include 
using namespace std;
int main(){
    double money;
    while (cin >> money){
        vector<double> arr(10, 0);
        for (int i=0; i<10; i++)
            arr[i] = i;
        for (int i=0; i<10; i++){
            int randval = rand() % (arr.size()-i);
            int temp = arr[randval];
            arr.erase(arr.begin()+randval);
            arr.push_back(temp);
        }
        for (int i=0; i<10; i++)
            cout << arr[i] << endl;
    }
    return 0;
}

实现单例模式

有两种方式,一个是懒汉式,一个是饿汉式。懒汉式需要考虑加锁。

#include 
#include 
using namespace std;

class singleInstance{
public:
    static singleInstance* GetsingleInstance(){
        if (instance == NULL){
            pthread_mutex_lock(&mutex);//mlock.lock();
            if (instance == NULL){
                instance = new singleInstance();
            }
            pthread_mutex_unlock(&mutex);//mlock.unlock();
        }
        return instance;
    };
    ~singleInstance(){};
    static pthread_mutex_t mutex;//mutex mlock; 加锁互斥
private:// 涉及创建对象的函数都设置为private
    singleInstance(){};
    singleInstance(const singleInstance& other){};
    singleInstance& operator=(const singleInstance& other){ return *this; };
    static singleInstance* instance;
};

//懒汉式,静态变量需要定义
singleInstance* singleInstance::instance = nullptr;
pthread_mutex_t singleInstance::mutex;

int main(){
    // 因为没有办法创建对象,就得采用静态成员函数的方法返回静态成员变量
    singleInstance *s = singleInstance::GetsingleInstance();
    //singleInstance *s1 = new singleInstance(); // 报错
    cout << "Hello World";
    delete s;  // 防止内存泄露
    return 0;
}

下面是饿汉式:

#include 
#include 
using namespace std;

class singleInstance{
public:
    static singleInstance* GetsingleInstance(){ // 饿汉式,直接创建一个对象,不需要加锁
        static singleInstance instance;
        return &instance;
    };
    ~singleInstance(){};
private:// 涉及创建对象的函数都设置为private
    singleInstance(){};
    singleInstance(const singleInstance& other){};
    singleInstance& operator=(const singleInstance& other){ return *this; };
};

int main(){
    // 因为没有办法创建对象,就得采用静态成员函数的方法返回
    singleInstance *s = singleInstance::GetsingleInstance();
    //singleInstance *s1 = new singleInstance(); // 报错
    cout << "Hello World";
    return 0;
}

实现strcpy

char* Strcpy(char* dst, const char* source){
	assert(dst != NULL && source != NULL);
	char* re = dst;
	while ((*dst++ == *source++) != '\0');
	return re;
}

shared共享指针实现

#include 
#include 
using namespace std;

template <typename T>
class mysharedPtr {
public:
	mysharedPtr(T* p = NULL);
	~mysharedPtr();
	mysharedPtr(const mysharedPtr<T>& other);
	mysharedPtr<T>& operator=(const mysharedPtr<T>& other);
private:
	T* m_ptr;
	unsigned int* m_count;
};

template <typename T>
mysharedPtr<T>::mysharedPtr(T* p) {
	m_ptr = p;
	m_count = new unsigned int(0);
	++(*m_count);
	cout << "Constructor is succeed!" << endl;
}

template <typename T>
mysharedPtr<T>::~mysharedPtr() {
	--(*m_count);
	if ((*m_count) == 0) {
		delete[] m_ptr;
		m_ptr = NULL;
		delete[] m_count;
		m_count = NULL;
		cout << "Destructor is succeed!" << endl;
	}
}

template <typename T>
mysharedPtr<T>::mysharedPtr(const mysharedPtr<T>& other) {
	m_ptr = other.m_ptr;
	m_count = other.m_count;
	++(*m_count);
	cout << "Copy constructor is succeed!" << endl;
}

template <typename T>
mysharedPtr<T>& mysharedPtr<T>::operator=(const mysharedPtr<T>& other) {
	// 《C++ primer》:“这个赋值操作符在减少左操作数的使用计数之前使other的使用计数加1,
	// 从而防止自身赋值”而导致的提早释放内存
	++(*other.m_count);
	--(*m_count);
	// 将左操作数对象的使用计数减1,若该对象的使用计数减至0,则删除该对象
	if ((*m_count) == 0) {
		delete[] m_ptr;
		m_ptr = NULL;
		delete[] m_count;
		m_count = NULL;
		cout << "Left side object is deleted!" << endl;
	}
	m_ptr = other.m_ptr;
	m_count = other.m_count;
	cout << "Assignment operator overloaded is succeed!" << endl;
	return *this;
}

int main() {
	// Test Constructor and Assignment Operator Overloaded
	mysharedPtr<int> p1(new int(0));
	p1 = p1;
	// Test Copy Constructor
	mysharedPtr<int> p2(p1);
	// Test Assignment Operator Overloaded
	mysharedPtr<int> p3(new int(1));
	p3 = p1;
	system("Pause");
	return 0;
}

简单工程模式

#include 
#include 
using namespace std;

//产品类(抽象类,不能实例化)
class Product{
public:
    Product(){};
    virtual void show()=0;  //纯虚函数
};

class productA:public Product{
public:
    productA(){};
    void show(){ cout << "product A create!" << endl; };
    ~productA(){};
};

class productB:public Product{
public:
    productB(){};
    void show(){ cout << "product B create!" << endl; };
    ~productB(){};
};

class simpleFactory{ // 工厂类

public:
    simpleFactory(){};
    Product* product(const string str){
        if (str == "productA")
            return (new productA());
        if (str == "productB")
            return (new productB());
        return NULL;
    };
};

int main(){
    simpleFactory obj; // 创建工厂
    Product* pro; // 创建产品

    pro = obj.product("productA");
    pro->show(); // product A create!
    delete pro;

    pro = obj.product("productB");
    pro->show(); // product B create!
    delete pro;

    return 0;
}

抽象工程模式

#include 
#include 
using namespace std;

//产品类(抽象类,不能实例化)
class Product{
public:
    Product(){}
    virtual void show()=0;  //纯虚函数
};

//产品A
class ProductA:public Product{
public:
    ProductA(){}
    void show(){ cout<<"product A create!"<<endl; };
};

//产品B
class ProductB:public Product{
public:
    ProductB(){}
    void show(){ cout<<"product B create!"<<endl; };
};

class Factory{//抽象类
public:
    virtual Product* CreateProduct()=0;
};

class FactorA:public Factory{//工厂类A,只生产A产品
public:
    Product* CreateProduct(){
        return (new ProductA());
    }
};

class FactorB:public Factory{//工厂类B,只生产B产品
public:
    Product* CreateProduct(){
        return (new ProductB());
    }
};

int main(){

    Product* _Product = nullptr;
    auto MyFactoryA = new FactorA();
    _Product = MyFactoryA->CreateProduct();// 调用产品A的工厂来生产A产品
    _Product->show();
    delete _Product;

    auto MyFactoryB=new FactorB();
    _Product=MyFactoryB->CreateProduct();// 调用产品B的工厂来生产B产品
    _Product->show();
    delete _Product;

    getchar();
    return 0;
}

循环队列实现

class MyCircularQueue {
private:
    vector<int> data;
    int head;
    int tail;
    int size;
public:
    /** Initialize your data structure here. Set the size of the queue to be k. */
    MyCircularQueue(int k) {
        data.resize(k);
        head = -1;
        tail = -1;
        size = k;
    }
    
    /** Insert an element into the circular queue. Return true if the operation is successful. */
    bool enQueue(int value) {
        if (isFull()) {
            return false;
        }
        if (isEmpty()) {
            head = 0;
        }
        tail = (tail + 1) % size;
        data[tail] = value;
        return true;
    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    bool deQueue() {
        if (isEmpty()) {
            return false;
        }
        if (head == tail) {
            head = -1;
            tail = -1;
            return true;
        }
        head = (head + 1) % size;
        return true;
    }
    
    /** Get the front item from the queue. */
    int Front() {
        if (isEmpty()) {
            return -1;
        }
        return data[head];
    }
    
    /** Get the last item from the queue. */
    int Rear() {
        if (isEmpty()) {
            return -1;
        }
        return data[tail];
    }
    
    /** Checks whether the circular queue is empty or not. */
    bool isEmpty() {
        return head == -1;
    }
    
    /** Checks whether the circular queue is full or not. */
    bool isFull() {
        return ((tail + 1) % size) == head;
    }
};

**
 * Your MyCircularQueue object will be instantiated and called as such:
 * MyCircularQueue obj = new MyCircularQueue(k);
 * bool param_1 = obj.enQueue(value);
 * bool param_2 = obj.deQueue();
 * int param_3 = obj.Front();
 * int param_4 = obj.Rear();
 * bool param_5 = obj.isEmpty();
 * bool param_6 = obj.isFull();
 */

你可能感兴趣的:(蒋豆芽的秋招之路,c语言,案例,项目开发)