《数据结构算法与应用 —— C++语言描述》学习笔记 — 字典 — 链表实现
Posted coding-hwz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《数据结构算法与应用 —— C++语言描述》学习笔记 — 字典 — 链表实现相关的知识,希望对你有一定的参考价值。
虽然在n个元素的有序数组上二分查找所需要的时间为 O ( l o g n ) O(logn) O(logn),但是有序链表上查找所需要的时间为 O ( n ) O(n) O(n)。为了提高有序链表的查找性能,可以在全部或部分节点上增加额外的指针。在查找时,通过这些指针,可以跳过链表的若干个节点,不必从左到右连续查看所有节点。
增加了额外的向前指针的链表叫做跳表。它采用随机技术来决定链表的哪些节点应增加向前指针,以及增加多少个指针。基于这种随机技术,跳表的查找、插入、删除的平均时间复杂度为 O ( l o g n ) O(logn) O(logn)。然而,最坏情况下的时间复杂度却变成 O ( n ) O(n) O(n)。
散列是用来查找、插入、删除的另一种随机方法。与跳表相比,它把操作时间提高到 O ( 1 ) O(1) O(1),但最坏情况下的时间复杂度仍为 O ( n ) O(n) O(n)。尽管如此,如果经常需要按序输出所有元素或按序查找元素,那么跳表的执行效率将优于散列。
一、字典
字典是由一些形如 (k,v) 的数对所组成的集合,其中 k 是关键字,v 是与关键字 k 对应的值。任意两个数对,其关键字都不等。
多重字典与字典类似,只是两个或更多的数对可以有相同的关键字。在韦氏字典中,一个词可能有多个词条,对应于不同的意义、发音等。这样的形式就是多重字典。
在一个多重字典中进行查找和删除操作时,需要消除歧义。就查找而言,有两种可能:
(1)查找任何一个具备给定关键字的数对;
(2)查找所有具备给定关键字的数对。
就删除操作而言,我们要求用户提供与给定关键字对应的所有数对,由用户选择删除哪些数对。此外,可以任意删除与给定关键字对应的一个数或所有数对。
查找操作可以按照给定的关键字,随机地存取字典中的数对。有些字典的应用还有另一种存取模式 — 顺序存取。在这种模式中,利用迭代器,按关键字的升值顺序逐个查找字典数对。本章设计的所有字典是现代吗既可以随机存取,也可以顺序存取。
二、抽象数据类型
/*************************************************
Author: coding-hwz
Date:2021-08-24
Description: 字典抽象类,用于提供字典接口操作
**************************************************/
#pragma once
#include <utility>
template<typename Key, class Value>
class dictionary
{
public:
virtual ~dictionary() {};
/*
* @brief 判断字典是否为空
* @return true 空
* @return false 非空
*/
virtual bool empty() const = 0;
/*
* @brief 返回字典数据长度
* @return 字典数据长度
*/
virtual int size() const = 0;
/*
* @brief 查找给定key对应的值
* @param key 给定键
* @return 键值对对象
*/
virtual std::pair<Key, Value>* find(const Key& key) const = 0;
/*
* @brief 删除某键对应的键值对
* @param key 给定键
*/
virtual void erase(const Key& key) = 0;
/*
* @brief 向字典中插入新的键值对
* @param keyValue 键值对对象
*/
virtual void insert(const std::pair<Key, Value>& element) = 0;
};
三、链表描述
1、节点
/*************************************************
Author: coding-hwz
Date:2021-08-24
Description: 链表字典类,节点声明
**************************************************/
#pragma once
#include <utility>
template<typename Key, typename Value>
struct pairNode
{
std::pair<Key, Value> element;
pairNode* next;
};
2、接口声明
/*************************************************
Author: coding-hwz
Date:2021-08-24
Description: 链表字典类
**************************************************/
#pragma once
#include "dictionary.h"
#include "pairNode.h"
template<typename Key, typename Value>
class sortedChain : public dictionary<Key, Value>
{
public:
typedef struct pairNode<Key, Value> node_type;
using value_type = typename std::pair<Key, Value>;
// copy control
sortedChain() = default;
sortedChain(const sortedChain& other);
sortedChain(sortedChain&& other);
virtual ~sortedChain() override;
sortedChain& operator=(const sortedChain& other);
sortedChain& operator=(sortedChain&& other);
virtual bool empty() const override;
virtual int size() const override;
virtual value_type* find(const Key& key) const override;
virtual void erase(const Key& key) override;
virtual void insert(const value_type& element) override;
private:
node_type* firstNode = nullptr;
std::size_t dictionarySize = 0;
/*
* @brief 交换两个字典的数据
* @param other 另一个字典对象
*/
void swap(sortedChain& other);
/*
* @brief 拷贝另一个字典的数据
* @param other 另一个字典对象
* @return 拷贝生成的临时对象
*/
sortedChain makeCopy(const sortedChain& other);
void makeCopyAndSwap(const sortedChain& other);
};
3、拷贝控制接口
template<typename Key, typename Value>
sortedChain<Key, Value>::sortedChain(const sortedChain& other)
{
makeCopyAndSwap(other);
}
template<typename Key, typename Value>
sortedChain<Key, Value>::sortedChain(sortedChain&& other)
{
swap(other);
}
template<typename Key, typename Value>
sortedChain<Key, Value>::~sortedChain()
{
while (firstNode != nullptr)
{
auto nextNode = firstNode->next;
delete firstNode;
firstNode = nextNode;
}
}
template<typename Key, typename Value>
sortedChain<Key, Value>& sortedChain<Key, Value>::operator=(const sortedChain& other)
{
makeCopyAndSwap(other);
return *this;
}
template<typename Key, typename Value>
sortedChain<Key, Value>& sortedChain<Key, Value>::operator=(sortedChain&& other)
{
swap(other);
return *this;
}
template<typename Key, typename Value>
void sortedChain<Key, Value>::swap(sortedChain& other)
{
using std::swap;
swap(dictionarySize, other.dictionarySize);
swap(firstNode, other.firstNode);
}
template<typename Key, typename Value>
sortedChain<Key, Value> sortedChain<Key, Value>::makeCopy(const sortedChain& other)
{
sortedChain returnChain;
if (other.firstNode == nullptr)
{
return returnChain;
}
returnChain.firstNode = new node_type(*other.firstNode);
auto currentNodeThis = returnChain.firstNode;
auto currentNodeOther = other.firstNode;
while (currentNodeOther->next != nullptr)
{
currentNodeThis->next = new node_type(*currentNodeOther->next);
currentNodeThis = currentNodeThis->next;
currentNodeOther = currentNodeOther->next;
}
dictionarySize = other.dictionarySize;
return returnChain;
}
template<typename Key, typename Value>
inline void sortedChain<Key, Value>::makeCopyAndSwap(const sortedChain& other)
{
auto copySortedChain = makeCopy(other);
swap(copySortedChain);
}
这里我们主要是通过 makeCopy 和 swap 接口实现的拷贝和移动功能
4、容量接口
template<typename Key, typename Value>
bool sortedChain<Key, Value>::empty() const
{
return dictionarySize == 0;
}
template<typename Key, typename Value>
int sortedChain<Key, Value>::size() const
{
return dictionarySize;
}
5、修改接口
template<typename Key, typename Value>
auto sortedChain<Key, Value>::find(const Key& key) const -> sortedChain<Key, Value>::value_type*
{
auto currentNode = firstNode;
while (currentNode != nullptr && currentNode->element.first != key)
{
currentNode = currentNode->next;
}
if (currentNode != nullptr && currentNode->element.first == key)
{
return ¤tNode->element;
}
return nullptr;
}
template<typename Key, typename Value>
void sortedChain<Key, Value>::erase(const Key& key)
{
node_type* currentNode = firstNode;
node_type* prevNode = nullptr;
while (currentNode != nullptr && currentNode->element.first != key)
{
prevNode = currentNode;
currentNode = currentNode->next;
}
if (currentNode != nullptr && currentNode->element.first == key)
{
if (currentNode == firstNode)
{
firstNode = firstNode->next;
}
else
{
prevNode->next = currentNode->next;
}
delete currentNode;
dictionarySize--;
}
}
template<typename Key, typename Value>
inline void sortedChain<Key, Value>::insert(const value_type& element)
{
node_type* afterNode = firstNode;
node_type* beforeNode = nullptr;
while (afterNode != nullptr && afterNode->element.first < element.first)
{
beforeNode = afterNode;
afterNode = afterNode->next;
}
if (afterNode != nullptr && afterNode->element.first == element.first)
{
// 替换旧数据
afterNode->element = element;
return;
}
auto newNode = new node_type({ element, afterNode });
if (afterNode == firstNode)
{
firstNode = newNode;
}
else
{
beforeNode->next = newNode;
}
dictionarySize++;
}
以上是关于《数据结构算法与应用 —— C++语言描述》学习笔记 — 字典 — 链表实现的主要内容,如果未能解决你的问题,请参考以下文章