数据结构与算法分析--代码
参考书籍:[1]Clifford A.Shaffer.数据结构与算法分析[M].北京:电子工业出版社,2020.
Chapter 4 Lists, Stacks and Queues
4.1 Lists 线性表
4.1.1 Array-based Lists 顺序表
arraylist.h
#pragma once
#include<iostream>
using namespace std;
template <typename E>
class List //arraylist
{
private:
int maxSize;
int listSize;
int curr;
E* listArray;
public:
List(int size)
{
maxSize = size;
listSize = curr = 0;
listArray = new E[maxSize];
}
~List()
{
delete[] listArray;
}
void clear()
{
delete[] listArray;
listSize = curr = 0;
listArray = new E[maxSize];
}
void insert(const E& item)//在curr处加一个元素并把其它元素后移
{
if (listSize >= maxSize)
{
cout << "List capacity exceeded" << endl;
return;
}
for (int i = listSize; i > curr; i--)
{
listArray[i] = listArray[i - 1];
}
listArray[curr] = item;
listSize++;
}
void append(const E& item)//在元素最后加一个元素,不超过列表总长
{
if (listSize >= maxSize)
{
cout << "List capacity exceeded" << endl;
return;
}
listArray[listSize++] = item;
}
void remove()//除去curr处的元素并把其它元素前移
{
if (curr < 0 || curr >= listSize)
{
cout << "No element" << endl;
return;
}
//E it = listArray[curr];可以返回删除的值
for (int i = curr; i < listSize - 1; i++)
listArray[i] = listArray[i + 1];
listSize--;
return;
}
void printlist()//打印列表元素
{
int i = 0;
while (i != listSize)
{
cout << listArray[i] << ' ';
i++;
}
}
void moveToStart()//curr移到头部
{
curr = 0;
}
void moveToEnd()//curr移到尾部
{
curr = listSize;
}
void prev()//curr前移
{
if (curr != 0) curr--;
}
void next()//curr后移
{
if (curr < listSize) curr++;
}
int length() const//返回列表长度
{
return listSize;
}
int currPos() const//返回curr位置
{
return curr;
}
void moveToPos(int pos)//curr移到pos位置
{
if (pos < 0 || pos >= listSize)
{
cout << "No current element" << endl;
return;
}
curr = pos;
}
const E& getValue() const//返回curr的值
{
if (curr < 0 || curr >= listSize)
{
cout << "No current element" << endl;
return 0;
}
return listArray[curr];
}
};
模板一般整个放到头文件中
模板会在被使用的时候实例化,在这之前并不会生成二进制的机器码,所以必须在用到的地方被引入,如果把实现放到cpp里的话,引用到这个模板的地方虽然包含了相应的头文件知道有符号(比如函数)的存在,却不知道这个符号到底要做什么(函数没有实现),就会出错。–引用老师的解释
arraylist.cpp
#include"list.h"
#include<iostream>
int main()
{
List<int> a(10);
a.append(1);
a.append(2);
a.append(3);
a.moveToPos(2);
a.insert(4);
a.moveToStart();
a.remove();
a.printlist();
return 0;//结果输出2 4 3
}
4.1.2 Singly Linked List 单链表
用单链表实现排序功能
#include<iostream>
using namespace std;
template<class T>
class node
{
public:
T data;
node* next;
node()
{
data = 0;
next = NULL;
}
node(T d, node* next = NULL)
{
data = d;
next = next;
}
};
template<class T>
class List:public node<T>
{
private:
node<T>* head;
node<T>* tail;
node<T>* curr;
int size;
public:
List(T a[],int size)
{
size = size;
curr = tail = head = new node<T>();
for (int i = 0; i < size; i++)
{
curr->next = new node<T>(a[i], NULL);
tail = curr->next;
curr = curr->next;
}
}
void Print(List list,int size)
{
curr = head;
for (int i = 0; i < size; i++)
{
cout << curr->next->data << " ";
curr = curr->next;
}
cout << endl;
}
bool Compare(T a, T b)
{
if (a < b)
return true;
return false;
}
void SelectSort(List list,int size)//From smallest to largest
{
node<T>* currTem;
T temp;
for (int i = 0; i < size-1; i++)
{
curr = head->next;
currTem = curr;
for (int j = 0; j < size-i-1; j++)
{
currTem = currTem->next;
if (Compare(curr->data, currTem->data))
{
curr = currTem;//curr save the largest place
}
}
temp = curr->data;
curr->data = currTem->data;
currTem->data = temp;
}
}
};
int main()
{
cout << "Example 1" << endl;
int a[5] = { 10,8,34,26,5 };
List<int> list1(a,5);
cout<<"The original order:"<<endl;
list1.Print(list1, 5);
list1.SelectSort(list1,5);
cout << "The sorted order:" << endl;
list1.Print(list1, 5);
cout << endl;
}
Chapter 5 Binary Tree
5.3 Binary Tree Node Implementations 二叉树实现
BinNode.h
template<typename E>
class BinNode
{
private:
E it;
BinNode* lc;
BinNode* rc;
public:
BinNode()
{
lc = rc = NULL;
}
BinNode(E e, BinNode* l, BinNode* r)
{
it = e;
lc = l;
rc = r;
}
E& element()
{
return it;
}
void setElement(const E& e)
{
it = e;
}
BinNode* left() const
{
return lc;
}
void setLeft(BinNode* b)
{
lc = b;
}
BinNode* right() const
{
return rc;
}
void setRight(BinNode* b)
{
rc = b;
}
bool isLeaf()
{
return (lc == NULL) && (rc == NULL);
}
};
BinTree.h
#include<queue>
#include"BinNode.h"
template<typename E>
class BinTree
{
private:
BinNode<E>* root;//根结点
public:
//构造函数
BinTree()
{
root = NULL;
}
//析构函数
~BinTree()
{
clear(root);
}
//前序遍历输入一棵二叉树
BinNode<E>* createBinTree()
{
E ele;
cin >> ele;
BinNode<E>* rt;
if (ele == '#') rt = NULL;
else
{
rt = new BinNode<E>;
rt->setElement(ele);
rt->setLeft(createBinTree());
rt->setRight(createBinTree());
}
return rt;//返回根结点
}
//销毁二叉树
void clear(BinNode<E>* r)
{
if (r == NULL) return;//空树,直接返回
//只有一个结点
if (r->left() == NULL && r->right() == NULL)
{
delete r;
r = NULL;
return;
}
//大于一个结点,递归销毁左子树与右子树
clear(r->left());
clear(r->right());
delete r;
r = NULL;
}
//返回根节点
BinNode<E>* Root()
{
return root;
}
//设置根节点
void setRoot(BinNode<E>* r)
{
root = r;
}
//判断二叉树是否为空
bool isEmpty(BinNode<E>* r)
{
return root == NULL;
}
//层次遍历
void levelorder(BinNode<E>* r)
{
queue<BinNode<E>*> q;
//将根结点入队
if (r) q.push(r);
BinNode<E>* temp;
while (!q.empty())
{
//temp赋为队首的根结点
temp = q.front();
//将队首的根结点出队
q.pop();
cout << temp->element() << ' ';
//如果该结点的左右结点存在,分别入队
if (temp->left()) q.push(temp->left());
if (temp->right()) q.push(temp->right());
}
}
//二叉树高度
int BinTreeHeight(BinNode<E>* r)
{
if (r == NULL) return 0;
else return max(BinTreeHeight(r->left()), BinTreeHeight(r->right())) + 1;
}
//二叉树结点数
int count(BinNode<E>* r)
{
if (r == NULL) return 0;
else return 1 + count(r->right()) + count(r->left());
}
};
BinTree.cpp
#include <iostream>
using namespace std;
#include"BinTree.h"
int main()
{
BinTree<char> tree;
BinNode<char>* rt;
cout << "请以前序遍历的顺序输入一棵树(结点元素类型为字符型),空节点以#代替。" << endl;
cout << "例如:AB##C##(必须是满二叉树,且叶子都为#)" << endl;
rt = tree.createBinTree();
tree.setRoot(rt);
if (tree.isEmpty(rt)) cout << "这棵树是空树,结束操作\n";
else
{
cout << "这棵二叉树层次遍历的结果为:\n";
tree.levelorder(rt); cout << endl;
cout << "这棵二叉树的高度是:\n";
cout << tree.BinTreeHeight(rt) << endl;
//都把二叉树生成了也算一下结点数,用的是与算高度差不多的递归函数
cout << "这棵二叉树的结点个数是:\n";
cout << tree.count(rt) << endl;
}
return 0;
}
5.4 Binary Search Tree 二叉查找树(BST)
利用二叉查找树查找从小值到大值中间的数
BSTNode.h
#include<iostream>
using namespace std;
template<typename E>
class BSTNode
{
private:
E it;
BSTNode* lc;
BSTNode* rc;
public:
BSTNode()
{
lc = rc = NULL;
}
BSTNode(E e, BSTNode* l = NULL, BSTNode* r = NULL)
{
it = e; lc = l; rc = r;
}
//基础结点函数
E& element()
{
return it;
}
inline BSTNode* left() const
{
return lc;
}
void setLeft(BSTNode<E>* b)
{
lc = b;
}
inline BSTNode* right() const
{
return rc;
}
void setRight(BSTNode<E>* b)
{
rc = b;
}
};
BST.h
#include"BSTNode.h"
template<typename E>
class BST
{
private:
BSTNode<E>* root;//树根
int m = 0;//记录结点数
public:
//构造函数
BST()
{
root = NULL;
}
void setRoot(BSTNode<E>* b)
{
root = b;
}
BSTNode<E>* insert(BSTNode<E>* b, int val)
{
if (b == NULL)
{
BSTNode<E>* temp = new BSTNode<E>(val);
return temp;
}
else
{
if (val < b->element())
b->setLeft(insert(b->left(), val));//小于往左边插入元素
else b->setRight(insert(b->right(), val));//大于等于往右边插入元素
return b;
}
}
void printRange(BSTNode<E>* b, E low, E high)
{
if (b == NULL) return;
if (b->element() < low)//元素太小,向右查找
{
printRange(b->right(), low, high);
return;
}
if (b->element() > high)//元素太大,向左查找
{
printRange(b->left(), low, high);
return;
}
//元素适中,打印并向左右两边继续查找
printRange(b->left(), low, high);
cout << b->element() << ' ';
printRange(b->right(), low, high);
m++;
}
void getNode() {
cout << "\n经过" << m << "个结点" << endl;//检查经过结点数
}
};
BST.cpp
#include"BST.h"
int main()
{
BST<int> Tree;
BSTNode<int>* rt = NULL;
Tree.setRoot(rt);
cout << "请输入BST中的结点个数:\n";
int n, m;
cin >> n;
cout << "请依次输入" << n << "个结点的值(int):\n";
for (int i = 1; i <= n; i++)
{
cin >> m;
if (i == 1) rt = Tree.insert(rt, m);
else Tree.insert(rt, m);
}
cout << "输入小值low value和大值high value" << endl;
int l, h;
cin >> l;
cin >> h;
Tree.printRange(rt, l, h); //在中序排序下进行修改
Tree.getNode();
return 0;
}
5.5 max-heap 大顶堆
Heap.h
#include<iostream>
using namespace std;
template<typename E>
class Comp
{
public:
//比较优先级
static bool prior(E a, E b)
{
return a >= b;
}
};
template<typename E, typename Comp>
class heap {
private:
E* Heap;
int maxsize;
int n;
//堆的下沉调整
void siftdown(int pos) {
while (!isLeaf(pos)) {
int lc = leftchild(pos);
int rc = rightchild(pos);
if ((rc < n) && Comp::prior(Heap[rc], Heap[lc]))
lc = rc;
if (Comp::prior(Heap[pos], Heap[lc]))
return;
swap(Heap[pos], Heap[lc]);
pos = lc;
}
}
public:
void buildHeap()
{
for (int i = n / 2; i >= 0; i--)
siftdown(i);
}
heap(E* h, int num, int max) //构造函数
{
Heap = h;
n = num;
maxsize = max;
buildHeap();
}
bool isLeaf(int pos) const
{
return (pos >= n / 2) && (pos < n);
}
bool isEmpty()
{
return n == 0;
}
int leftchild(int pos) const
{
return 2 * pos + 1;
}
int rightchild(int pos) const
{
return 2 * pos + 2;
}
//删除堆的根结点
E removefirst() {
if (n <= 0)
{
cout << "Heap is empty" << endl;
return NULL;
}
swap(Heap[0], Heap[--n]);
if (n != 0)
siftdown(0);
return Heap[n];
}
};
Heap.cpp
#include"Heap.h"
using namespace std;
int main()
{
int n = 10;
int a[100] = {10,5,12,3,2,1,8,7,9,4};
heap< int, Comp<int> > hp(a, n, 100);
while (!hp.isEmpty())
cout << hp.removefirst() << endl;
cout << endl;
}
5.6 Huffman Coding Trees 哈夫曼编码树
有参考csnd(ChanJose:C++哈夫曼编码)
HuffTree.h
#ifndef HuffTree_h
#define HuffTree_h
#include <iostream>
using namespace std;
struct HuffmanNode {
int weight; // 权重
char ch; // 存储符号
string code; // 存储该符号对应的编码
int leftChild, rightChild, parent; // 左、右孩子,父结点
};
class HuffmanCode {
public:
HuffmanCode(int* arr,char* letter,int leafSize); // 构造函数
~HuffmanCode(); // 析构函数
void getMin(int& first, int& second, int parent); // 选取两个较小的元素
void Merge(int first, int second, int parent); // 合并
void Encode(int count); // 编码:利用哈夫曼编码原理对数据进行加密
private:
HuffmanNode* HuffmanTree; // 数组
};
// 构造函数
HuffmanCode::HuffmanCode(int* arr,char* letter,int len) {
HuffmanTree = new HuffmanNode[100]; // 分配空间
// 1.初始化HuffmanTree数组
for (int i = 0; i < (2 * len - 1); i++) { // 叶子结点为len,则树最多有2*len-1个结点
HuffmanTree[i].leftChild = HuffmanTree[i].rightChild = HuffmanTree[i].parent = -1;
HuffmanTree[i].code = "";
}
// 2.将权重和字符存入HuffmanTree数组
for (int i = 0; i < len; i++) {
HuffmanTree[i].ch = letter[i]; // 将数字转成对应的字符
HuffmanTree[i].weight = arr[i]; // 权重
}
// 3.选取两个较小值合并
int first, second; // 两个较小的结点
for (int i = len; i < (2*len-1) ; i++) { // 做leafSize-1趟
getMin(first, second, i); // 选取两个较小的元素
Merge(first, second, i); // 合并
}
}
// 析构函数
HuffmanCode::~HuffmanCode() {
delete[]HuffmanTree;
}
// 选取权值两个较小的元素
void HuffmanCode::getMin(int& first, int& second, int parent) {
int weight = 0;
int i;
// 找权重最小元素
for (i = 0; i < parent; i++) {
if (HuffmanTree[i].parent != -1) // 已选过,直接跳过
continue;
if (weight == 0) { // 第一次找到没选过的结点
weight = HuffmanTree[i].weight;
first = i;
}
else if (HuffmanTree[i].weight < weight) { // 权值更小
weight = HuffmanTree[i].weight;
first = i;
}
}
// 找权重次小元素
weight = 0;
for (i = 0; i < parent; i++) {
if (HuffmanTree[i].parent != -1 || i == first) // 已选过,直接跳过
continue;
if (weight == 0) { // 第一次找到没选过的结点
weight = HuffmanTree[i].weight;
second = i;
}
else if (HuffmanTree[i].weight < weight) { // 权值更小
weight = HuffmanTree[i].weight;
second = i;
}
}
}
// 合并
void HuffmanCode::Merge(int first, int second, int parent) {
HuffmanTree[first].parent = HuffmanTree[second].parent = parent; // 父结点
HuffmanTree[parent].leftChild = first; // 左孩子
HuffmanTree[parent].rightChild = second; // 右孩子
HuffmanTree[parent].weight = HuffmanTree[first].weight + HuffmanTree[second].weight; // 权值
}
// 编码:利用哈夫曼编码原理对数据进行加密
void HuffmanCode::Encode(int count) {
string code; // 存储符号的不定长二进制编码
int i, j, k, parent;
for (i = 0; i < count; i++) { // 从叶子结点出发
j = i;
code = ""; // 初始化为空
while (HuffmanTree[j].parent != -1) { // 往上找到根结点
parent = HuffmanTree[j].parent; // 父结点
if (j == HuffmanTree[parent].leftChild) // 如果是左孩子,则记为0
code += "0";
else // 右孩子,记为1
code += "1";
j = parent; // 上移到父结点
}
// 编码要倒过来:因为是从叶子往上走到根,而编码是要从根走到叶子结点
for (k = (int)code.size() - 1; k >= 0; k--)
HuffmanTree[i].code += code[k]; // 保存编码
cout << HuffmanTree[i].ch << "的编码为:" << HuffmanTree[i].code << " "<<endl;
}
}
#endif
HuffTree.cpp
#include "HuffTree.h"
int main() {
int count = 12;//字符数
int a[12] = { 2,3,5,7,11,13,17,19,23,31,37,41 };
char c[12] = { 'A','B','C','D','E','F','G','H','I','J','K','L' };
HuffmanCode st(a,c,count); // 对象
cout << "对字符串编码情况如下:" << endl;
st.Encode(count); // 编码
cout << endl;
cout << "n个字符编码的期望长度为[log(n)]+1" << endl;
}