堆排序
基本思路
父节点在数组里的序号为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);
}