秋招复习(1) - 重要数据结构和算法的代码实现

堆排序

基本思路

父节点在数组里的序号为i,则两个子节点分别为2 * i + 1 和 2 * i + 1,利用这种方式将整个数组模拟成了一个二叉树。先对整个数组建堆,完成之后数组第一个元素nums[0]就是最大/最小,然后将其交换到数组nums[size-1],在对前size-1的数组元素建堆,再把nums[0]交换到nums[size-2]。重复这个过程,即可完成对整个数组的排序。时间复杂度O(nlogn).

代码实现:

//用户交换堆顶元素到数组末尾
void Swap(int& a, int& b) {
	int tmp = a;
	a = b;
	b = tmp;
}

// curLen表示当前用于构造大根堆的数组长度
void SortCore(vector<int>& nums, int curLen,int curPos) {
	if (curLen <= 1) return;
	bool isLeftExist = 2 * curPos + 1 < curLen;
	bool isRightExist = 2 * curPos + 2 < curLen;
	if (!isLeftExist && !isRightExist) return;
	// 存在左节点,则先调整左节点
	if(isLeftExist)
		SortCore(nums, curLen, 2 * curPos + 1);
	// 存在右节点,则先调整右节点
	if(isRightExist)
		SortCore(nums, curLen, 2 * curPos + 2);
	// 找到左右节点里最大的
	int changePos = 0;
	if (isLeftExist) {
		changePos = 2 * curPos + 1;
		if (isRightExist && nums[2 * curPos + 2] > nums[2 * curPos + 1]) {
			changePos = 2 * curPos + 2;
		}
	}
	else {
		changePos = 2 * curPos + 1;
	}
	
	// 如果最大的字节点大于父节点,则交换
	if (nums[changePos] > nums[curPos]) {
		Swap(nums[changePos], nums[curPos]);
	}
}
// 堆排序入口
void Sort(vector<int>& nums) {
	int size = nums.size();
	//每次调整堆都确定一个最大的元素
	for (int i = size; i > 1; --i) {
		Sort(nums,i,0); // 对数组0-i范围内的建堆
		Swap(nums[0], nums[i - 1]); // 完成之后将最大的nuns[0]交换到末尾
	}
}

字典树(前缀树)

基本思路

实际就是保存当前节点的下一个所有可能的节点在一个数组中,为一颗26叉树(我这里只模拟了小写字符的前缀树,要模拟所有字符的话把数组增大到256就行了)。

代码实现

class TreeNode {
public:
	bool _isEnd; // 表示当前字母是不是字符串的最后一个
	TreeNode* _node[26]; // 保存当前字母的所有下一个字母节点
	static int newTimes; // 统计申请内存次数

public:
	TreeNode() {
		_isEnd = false;
		memset(_node, 0, sizeof(TreeNode*) * 26);
	}

	// 插入指定字符串
	void insert(string& s) {
		int size = s.size();
		TreeNode*  p = this;
		for (int i = 0; i < size; ++i) {
			if (p->_node[s[i] - 'a'] == NULL) {
				p->_node[s[i] - 'a'] = new TreeNode();
				++newTimes;
				p = p->_node[s[i] - 'a'];
			}
			else {
				p = p->_node[s[i] - 'a'];
			}
		}
		p->_isEnd = true;
	}

	// 搜索指定字符串是否存在
	bool search(string& s) {
		int size = s.size();
		TreeNode* p = this;
		for (int i = 0; i < size; ++i) {
			if (p->_node[s[i] - 'a'] == nullptr) return false;
			p = p->_node[s[i] - 'a'];
		}
		return p->_isEnd == true;
	}

	// 判断指定字符串为前缀的字母是否存在
	bool isPrefix(string& s){
		int size = s.size();
		TreeNode* p = this;
		for (int i = 0; i < size; ++i) {
			if (p->_node[s[i] - 'a'] == nullptr) return false;
			p = p->_node[s[i] - 'a'];
		}
		return true;
	}

	// 清理内存
	bool clear() {
		for (int i = 0; i < 26; ++i) {
			if (_node[i]) {
				_node[i]->clear();
				delete _node[i];
				--newTimes;
			}
		}
	    return TreeNode::newTimes == 0;
	}
};
int TreeNode::newTimes = 0;

观察者模式

#include <iostream>
#include <list>
using namespace std;
 
class Observer
{
public:
    virtual void Update(int) = 0;
};
 
class Subject
{
public:
    virtual void Attach(Observer *) = 0;
    virtual void Detach(Observer *) = 0;
    virtual void Notify() = 0;
};
 
class ConcreteObserver : public Observer
{
public:
    ConcreteObserver(Subject *pSubject) : m_pSubject(pSubject){}
 
    void Update(int value)
    {
        cout << "ConcreteObserver get the update. New State:" << value << endl;
    }
 
private:
    Subject *m_pSubject;
};
 
class ConcreteObserver2 : public Observer
{
public:
    ConcreteObserver2(Subject *pSubject) : m_pSubject(pSubject){}
 
    void Update(int value)
    {
        cout << "ConcreteObserver2 get the update. New State:" << value << endl;
    }
 
private:
    Subject *m_pSubject;
};
 
class ConcreteSubject : public Subject
{
public:
// 目标用于和观察者之间建立联系和通知的三个函数
    void Attach(Observer *pObserver);
    void Detach(Observer *pObserver);
    void Notify();
 
    void SetState(int state)
    {
        m_iState = state;
    }
 
private:
    std::list<Observer *> m_ObserverList;
    int m_iState;
};
 
void ConcreteSubject::Attach(Observer *pObserver)
{
    m_ObserverList.push_back(pObserver);
}
 
void ConcreteSubject::Detach(Observer *pObserver)
{
    m_ObserverList.remove(pObserver);
}
 
void ConcreteSubject::Notify()
{
    std::list<Observer *>::iterator it = m_ObserverList.begin();
    while (it != m_ObserverList.end())
    {
        (*it)->Update(m_iState);
        ++it;
    }
}
 
int main()
{
    // Create Subject
    ConcreteSubject *pSubject = new ConcreteSubject();
 
    // Create Observer
    Observer *pObserver = new ConcreteObserver(pSubject);
    Observer *pObserver2 = new ConcreteObserver2(pSubject);
 
    // Change the state
    pSubject->SetState(2);
 
    // Register the observer
    pSubject->Attach(pObserver);
    pSubject->Attach(pObserver2);
 
    pSubject->Notify();
 
    // Unregister the observer
    pSubject->Detach(pObserver);
 
    pSubject->SetState(3);
    pSubject->Notify();
 
    delete pObserver;
    delete pObserver2;
    delete pSubject;
}

LRU实现

#include <iostream>
#include <vector>
#include <map>
using namespace std;

struct Node {
	int key;
	int value;
	Node* pre, *next;
	Node(int k, int v) {
		key = k;
		value = v;
		pre = next = nullptr;
	}
};

class LRUCache {
	int _capacity;
	Node* _head;
	Node* _tail;
	map<int, Node*> mp;

public:

	LRUCache(int size) {
		_capacity = size;
		_head = _tail = nullptr;
	}

	//插入已有结点到头部
	void setHead(Node *node)
	{
		node->next = _head;
		node->pre = NULL;

		if (_head != NULL)
		{
			_head->pre = node;
		}
		_head = node;
		if (_tail == NULL)
		{
			_tail = _head;
		}
	}

	void remove(int k) {
		map<int, Node*>::iterator it = mp.find(k);
		if (it != mp.end()) {
			remove(it->second);
		}
	}

	//移除结点
	void remove(Node *node)
	{
		if (node->pre != NULL){
			node->pre->next = node->next;
		} else{
			_head = node->next;
		}

		if (node->next != NULL) {
			node->next->pre = node->pre;
		}
		else {
			_tail = node->pre;
		}
	}

	// 获取k对应的值并更新链表
	int get(int key)
	{
		map<int, Node*>::iterator it = mp.find(key);
		if (it != mp.end()) {
			Node* node = it->second;
			remove(node);
			setHead(node);
			return node->value;
		} else {
			return -1;
		}
	}

	// 插入元素
	void set(int key, int value)
	{
		map<int, Node *>::iterator it = mp.find(key);
		if (it != mp.end())
		{
			Node* node = it->second;
			node->value = value;
			remove(node);
			setHead(node);
		} else {
			Node* newNode = new Node(key, value);
			if (mp.size() >= _capacity)
			{
				map<int, Node*>::iterator iter = mp.find(_tail->key);
				remove(_tail);
				mp.erase(iter);
			}
			setHead(newNode);
			mp[key] = newNode;
		}
	}

	// 获取当前元素个数
	int getCurSizeAndShow() {
		Node* p = _head;
		int nums = 0;
		while (p) {
			++nums;
			cout << p->value << " ";
			p = p->next;
		}
		cout << endl;
		return nums;
	}
};


int main() {
	LRUCache lru(5);
	lru.set(1, 11);
	lru.set(2, 22);
	lru.set(3, 33);
	lru.set(4, 44);
	lru.set(5, 55);

	cout << "原始链表为:" ;
	lru.getCurSizeAndShow();
	lru.get(4);
	cout << "获取key为4的元素之后的链表:";
	lru.getCurSizeAndShow();  

	lru.set(6, 66);
	cout << "新添加一个key为6之后的链表:";
	lru.getCurSizeAndShow();

	lru.remove(3);
	cout << "移除key=3的之后的链表";
	lru.getCurSizeAndShow();

    return 0;
}

BitMap C++ 实现

class BitMap
{
public:
    BitMap(size_t num)
    {
        _v.resize((num >> 5) + 1); // 相当于num/32 + 1
    }

    void Set(size_t num) //set 1
    {
        size_t index = num >> 5; // 相当于num/32
        size_t pos = num % 32;
        _v[index] |= (1 << pos);
    }

    void ReSet(size_t num) //set 0
    {
        size_t index = num >> 5; // 相当于num/32
        size_t pos = num % 32;
        _v[index] &= ~(1 << pos);
    }

    bool HasExisted(size_t num)//check whether it exists
    {
        size_t index = num >> 5;
        size_t pos = num % 32;
        bool flag = false;
        if (_v[index] & (1 << pos))
            flag = true;
        return flag;

    }

private:
    vector<size_t> _v;
}; 

位运算实现加法

int add(int a, int b) {
	if (b == 0) return a; // 无进位才终止
	int sum = a ^ b; // 完成无进位的加法
	int carry = (a & b) << 1; // 检测有进位的地方,左移一位转化为和sum相加的数
	return add(sum, carry); // 递归完成整个加法
}

不使用临时变量实现int数据互换

// a + b有越界风险
void swap(int& a, int& b) {
	a = a + b;
	b = a - b;
	a = a - b;
}
// 使用位运算,完美
void swapAdv(int&a, int& b) {
	a = a ^ b;
	b = a ^ b; // 相当于 b = a ^ b ^ b,相同数字异或为零
	a = a ^ b;
}

全排列

这里的例子为求数组的全排列。
可以通过不断交换当前位置数字和后面数字的方式,每次确定一个位置的值,再通过递归求后面数组的全排列的形式来实现。

#include<vector>
#include<iostream>
using namespace std;

void swap(int& a, int& b) {
	int tmp = a;
	a = b;
	b = tmp;
}
void printVec(vector<int>& nums) {
	for (auto a : nums) {
		cout << a << " ";
	}
	cout << endl;
}
void fullPermutationCore(vector<int>& nums, int curPos, int size) {
	if (curPos == size - 1) {
		printVec(nums);
	}
	// 从curPos开始,每次通过交换确定curPos一个位置的值,再递归确定后方数组的所有排列
	for (int i = curPos; i < size; ++i) {
		swap(nums[curPos], nums[i]);
		fullPermutationCore(nums, curPos + 1, size);
		swap(nums[curPos], nums[i]);
	}
}
void fullPermutation(vector<int>& nums) {
	int size = nums.size();
	if (size == 0) {
		cout << "empty vector" << endl;
		return;
	}
	fullPermutationCore(nums, 0, size);
}

int main() {
	cout << "please input vector size: " << endl;
	int size = 0;
	cin >> size;
	cout << "please input vector:" << endl;
	vector<int> nums(size, 0);
	for (int i = 0; i < size; ++i) {
		cin >> nums[i];
	}
	fullPermutation(nums);

	return 0;
}

归并排序

需构造一个同样大小的临时数组来辅助完成归并过程。

void MergeSortCore(vector<int>& nums, vector<int>& numsTmp, int start, int end) {
	if (start == end) return;
	int mid = (start + end) / 2;
	// 先完成左右两部分排序
	MergeSortCore(numsTmp, nums, start, mid);
	MergeSortCore(numsTmp, nums, mid + 1, end);
	//再归并完成数组合并
	int i = start;
	int j = mid + 1;
	int curPos = start;
	while (i <= mid && j <= end) {
		if (numsTmp[i] < numsTmp[j]) {
			nums[curPos++] = numsTmp[i++];
		}
		else {
			nums[curPos++] = numsTmp[j++];
		}
	}
	while (i <= mid) {
		nums[curPos++] = numsTmp[i++];
	}
	while (j <= end) {
		nums[curPos++] = numsTmp[j++];
	}
}

void MergeSort(vector<int>& nums) {
	int size = nums.size();
	if (size < 2) return;
	vector<int> numsTmp(nums);
	MergeSortCore(nums, numsTmp, 0, size - 1);
}

快速排序

以每一小段数组的首元素做标准,设置左右两个哨兵不断寻找比首元素大和小的数字进行交换,最后将首元素和哨兵碰头处的元素进行交换,确定首元素的最终位置。每次排序确定一个元素的最终位置。

void swap(int& a, int& b) {
	int tmp = a;
	a = b;
	b = tmp;
}

void QuickSortCore(vector<int>& nums, int start, int end) {
	if (end - start < 1) return;
	// 这里必须从start开始,如果初始i = start + 1,则数组有序时也会发生swap(nums[start], nums[i])操作,致使数组无序
	int i = start; 
	int j = end;
	while (i < j) {
		while (nums[j] >= nums[start] && j > i) {
			--j;
		}
		while (nums[i] <= nums[start] && j > i) {
			++i;
		}
		if (j > i) {
			swap(nums[i], nums[j]);
		}
	}
	swap(nums[start], nums[i]);
	QuickSortCore(nums, start, i - 1);
	QuickSortCore(nums, i + 1, end);
}
void QuickSort(vector<int>& nums) {
	int size = nums.size();
	if (size < 2) return;
	QuickSortCore(nums, 0, size - 1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋风遗梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值