凸包/基数排序
好久没写博客了今天上交一篇关于数据结构作业的博客8~
求凸包,O(nlogn)
// 求凸包,不采用任何链表或者arrayList,直接采用裸数组,实质一样(其实是我不想写双向链表了...哭T_T)
#include <iostream>
#include <algorithm>
using namespace std;
int count = 0; // 凸包中点的个数
int n; // 输入元素个数
// 点对象
struct point
{
int x, y; // 不想判断精度所以干脆不用double
};
point input[100], output[100]; // 输入的点和输出的点
// 极角排序
bool cmp(const point& a, const point& b)
{
return (a.x < b.x) || (a.x == b.x && a.y < b.y); // 选取最左下角的元素作极点
}
int xmul(const point& a, const point& b, const point& c) // 计算叉乘
{
return (b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y);
}
// 计算上下凸包(因为我们取的是左下角元素作极点)
void andrew()
{
sort(input, input + n, cmp);
// 上凸包
for (int i = 0; i < n; i++) {
while (::count > 1 && xmul(output[::count - 2], output[::count - 1], input[i]) < 0)
::count--;
output[::count++] = input[i];
}
int k = ::count;
// 下凸包
for (int i = n - 2; i > 0; i--) {
while (::count > k && xmul(output[::count - 2], output[::count - 1], input[i]) < 0)
::count--;
output[::count++] = input[i];
}
if (n > 1)
::count--;
}
int main()
{
cout << "输入点数:";
cin >> n;
for (int i = 0; i < n; i++) {
cin >> input[i].x >> input[i].y;
}
for (int i = 0; i < n; i++) {
cout << "Point:" << i + 1 << ": (" << input[i].x << "," << input[i].y << ")" << endl;
}
andrew();
cout << "In convex:" << endl;
for (int i = 0; i < ::count; i++) {
cout << "Point:" << i + 1 << ": (" << output[i].x << "," << output[i].y << ")" << endl;
}
return 0;
}
基数排序,O(d*(radix+n)),其中d是关于radix和n的一个数
如下首先是我们类的实现
#ifndef CHAIN_H_
#define CHAIN_H
#include <iostream>
#include <sstream>
#include <iterator>
using namespace std;
template <typename T>
struct chainNode
{
T element;
chainNode<T>* next;
chainNode() = default;
chainNode(const T& theElement) :element(theElement) {}
chainNode(const T& theElement, chainNode<T>* theNext) :element(theElement), next(theNext) {}
operator int() const { return element; }
};
template <typename T>
class chain
{
public:
chain(int initialcapacity = 10);
chain(const chain<T>& theChain);
~chain();
int size() const { return listSize; }
bool empty() const { return listSize == 0; }
void insert(int theIndex, const T& theElement);
//void erase(const T& theElement);
void erase(int theIndex);
T& get(int theIndex) const;
void binSort(int range);
void output(ostream& os) const;
void reverse();
void clear();
void merge(chain<T>& first, chain<T>& second);
class iterator;
iterator begin() const { return iterator(firstNode); }
iterator end() const { return iterator(nullptr); }
class iterator
{
public:
typedef forward_iterator_tag iterator_catagory;
typedef ptrdiff_t diffrence_type;
typedef T& reference_type;
typedef T value_type;
typedef T* pointer;
iterator(chainNode<T>* it) { iter = it; }
iterator(const iterator& it) { iter = it.iter; }
~iterator() = default;
T& operator*() const { return iter->element; }
T* operator->() const { return &iter->element; }
iterator& operator++()
{
iter = iter->next;
return *this;
}
iterator operator++(int n)
{
iterator old = iter;
iter = iter->next;
return old;
}
bool operator==(const iterator it) { return iter == it.iter; }
bool operator!=(const iterator it) { return iter != it.iter; }
private:
chainNode<T>* iter;
};
private:
chainNode<T>* firstNode;
int listSize;
};
template <typename T>
chain<T>::chain(int initialcapacity)
{
listSize = 0;
firstNode = nullptr;
}
template <typename T>
chain<T>::chain(const chain<T>& theChain)
{
listSize = theChain.listSize;
if (listSize == 0)
{
firstNode = nullptr;
return;
}
chainNode<T>* sourceNode = theChain.firstNode;
firstNode = new chainNode<T>(sourceNode->element);
sourceNode = sourceNode->next;
chainNode<T>* targetNode = firstNode;
while (sourceNode != nullptr)
{
targetNode->next = new chainNode<T>(sourceNode->element);
targetNode = targetNode->next;
sourceNode = sourceNode->next;
}
targetNode->next = nullptr;
}
template <typename T>
chain<T>::~chain()
{
while (firstNode != nullptr)
{
chainNode<T>* deleteNode = firstNode;
firstNode = firstNode->next;
delete deleteNode;
// equivalent notion
/*chainNode<T>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;*/
}
}
template <typename T>
void chain<T>::insert(int theIndex, const T& theElement)
{
if (theIndex < 0 || theIndex > listSize)
{
ostringstream err;
err << "Index out of range" << endl;
throw err.str();
}
if (theIndex == 0)
firstNode = new chainNode<T>(theElement, firstNode);
else
{
chainNode<T>* currNode = firstNode;
for (int i = 0; i < theIndex - 1; i++)
currNode = currNode->next;
currNode->next = new chainNode<T>(theElement, currNode->next);
}
listSize++;
}
//template <typename T>
//void chain<T>::erase(const T& theElement)
//{
// // 两种写法
// // 写法1:找到索引,O(n)
// int index = 0;
// chainNode<T>* currNode = firstNode;
// for (; index < listSize; index++)
// {
// if (currNode->element == theElement)
// break;
// currNode = currNode->next;
// index++;
// }
// if (index == listSize)
// return;
// currNode = firstNode;
// chainNode<T>* deleteNode;
// if (index == 0)
// {
// deleteNode = firstNode;
// firstNode = firstNode->next;
// }
// else
// {
// for (int i = 0; i < index - 1; i++)
// currNode = currNode->next;
// deleteNode = currNode->next;
// currNode->next = deleteNode->next;
// }
// delete deleteNode;
// listSize--;
//
// // 写法2:recursion式
//}
template <typename T>
void chain<T>::erase(int theIndex)
{
if (theIndex < 0 || theIndex >= listSize)
throw;
chainNode<T>* deleteNode;
if (theIndex == 0)
{
deleteNode = firstNode;
firstNode = firstNode->next;
}
else
{
chainNode<T>* currNode = firstNode;
for (int i = 0; i < theIndex - 1; i++)
currNode = currNode->next;
deleteNode = currNode->next;
currNode->next = currNode->next->next;
}
delete deleteNode;
listSize--;
}
template <typename T>
T& chain<T>::get(int theIndex) const
{
if (theIndex < 0 || theIndex >= listSize)
{
ostringstream err;
err << "Index out of range!" << endl;
throw err.str();
}
chainNode<T>* currNode = firstNode;
for (int i = 0; i < theIndex; i++)
currNode = currNode->next;
return currNode->element;
}
template <typename T>
void chain<T>::binSort(int range)
{
chainNode<T>** bottom, ** top;
bottom = new chainNode<T> * [range + 1];
top = new chainNode<T> * [range + 1];
for (int b = 0; b <= range; b++)
bottom[b] = nullptr;
for (;firstNode != nullptr;firstNode = firstNode->next)
{
int theBin = firstNode->element;
if (bottom[theBin] == nullptr)
bottom[theBin] = top[theBin] = firstNode;
else
{
top[theBin]->next = firstNode;
top[theBin] = firstNode;
}
}
chainNode<T>* y = nullptr;
for (int theBin = 0; theBin <= range; theBin++)
{
if (bottom[theBin] != nullptr)
{
if (y == nullptr)
firstNode = bottom[theBin];
else
y->next = bottom[theBin];
y = top[theBin];
}
}
if (y != nullptr)
y->next = nullptr;
delete[]bottom;
delete[]top;
}
template <typename T>
void chain<T>::output(ostream& os) const
{
chainNode<T>* currNode = firstNode;
while (currNode != nullptr)
{
os << currNode->element << " ";
currNode = currNode->next;
}
}
template <typename T>
void chain<T>::reverse()
{
// 方法也有两种,其中一种是recursion
// 方法1:原地逆转,O(n)
if (firstNode == nullptr || firstNode->next == nullptr)
return;
chainNode<T>* last = nullptr, * curr = firstNode, * next = nullptr;
while (curr != nullptr)
{
next = curr->next;
curr->next = last;
last = curr;
curr = next;
}
firstNode = last;
// 方法2不表
}
template <typename T>
void chain<T>::clear()
{
while (firstNode != nullptr)
{
chainNode<T>* nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
listSize = 0;
firstNode = nullptr;
}
template <typename T>
void chain<T>::merge(chain<T>& first, chain<T>& second)
{
chain<T>::iterator iter1 = first.begin();
chain<T>::iterator iter2 = second.begin();
while (iter1 != nullptr && iter2 != nullptr)
{
if (*iter1 <= *iter2) this->insert(listSize, *iter1++);
else this->insert(listSize, *iter2++);
}
while (iter1 != nullptr) this->insert(listSize, *iter1++);
while (iter2 != nullptr) this->insert(listSize, *iter2++);
first.clear();
second.clear();
}
#endif
根据上述类写出基数排序的代码
#include "链表和结构定义.h"
// 基数排序的实现,基本思想基于箱子排序
//
//struct studentRecord
//{
// int score;
// studentRecord() = default;
// studentRecord(int score) :score(score) {}
// studentRecord(const studentRecord& stuRec) :score(stuRec.score) {}
// ~studentRecord() = default;
// operator int() { return score; }
//};
// 类外方法,时间复杂度O(d*(radix+n)),d是n对radix的位数
void radixSort(chain<int>& theChain, int radix)
{
int d = 0; // 确定基数排序的最大位数
int len = theChain.size(); // 直接取chain的长度防止反复调用函数带来的开销
for (int i = 0; i < len; i++) { // O(listSize^2)
int temp = theChain.get(i);
int count = 0;
do {
temp /= radix;
count++;
} while (temp);
if (d < count)
d = count;
}
chain<int>* theBin = new chain<int>[radix+1]; // radixSort关键思想,箱子排序
int base = 1;
for (int i = 1; i <= d; i++) { // d次箱子排序
for (int j = 0; j < len; j++) { // 节点分配 O(listSize)
int bin = theChain.get(0);
theChain.erase(0);
theBin[bin / base % radix].insert(0, bin);
}
for (int b = radix; b >= 0; b--) { // 收获节点O(radix)
while (!theBin[b].empty()) {
int bin = theBin[b].get(0);
theBin[b].erase(0);
theChain.insert(0, bin);
}
}
base *= radix; // 下一次需要从高位算起
}
delete[]theBin;
}