数据结构与算法分析-代码


参考书籍:[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;
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值