《算法导论》 — Chapter 10 基本数据结构
2015-07-06 17:15
691 查看
序
在本章中,要讨论如何通过使用了指针的简单数据结构表示动态集合。有很多的复杂的数据结构可以用指针来构造,本章介绍几种基本数据结构,包括栈、队列、链表,以及有根树。GitHub 第十章 程序实现代码
栈
栈和队列都是动态集合,在这种结构中delete操作去掉的元素是预先规定好的。栈数据结构实现的是一种先进后出(FILO)的策略。作用于栈上的Insert操作称为压入Push,而无参数的Delete操作称为弹出Pop。本章讨论的栈是用数组实现,数据结构定义为(CStack.h):
#ifndef _CSTACK_H #define _CSTACK_H #include <iostream> class CStack{ public: CStack(); ~CStack(); int getTop() { return data[top]; } bool empty() { return top == -1; } bool full() { return top == (maxSize - 1); } void push(int x); void pop(); void display(); private: int *data; int top; const int maxSize = 100; }; #endif
如上所示,类CStack表示一个自定义栈,其包含数据成员data这样一个动态数组存储元素,top为当前栈顶元素的下标,当top==-1时表示栈空,当top==maxSize-1时表示栈满。
类实现(CStack.cpp)如下:
#include "CStack.h" #include <iostream> CStack::CStack() { top = -1; data = new int[maxSize]; } CStack::~CStack() { delete data; } void CStack::push(int x) { if (full()) { std::cout << "栈已满!" << std::endl; return; } else top = top + 1; data[top] = x; } void CStack::pop() { if (empty()) { std::cout << "栈空!" << std::endl; return; } else std::cout << data[top--] << std::endl; } void CStack::display() { if (empty()) { std::cout << "栈空!" << std::endl; return; } for (int i = 0; i <= top; i++) std::cout << data[i] << "\t"; std::cout << std::endl; }
下面给出对以上自定义栈的测试程序(main.cpp)与测试结果:
#include "CStack.h" #include <iostream> #include <cstdlib> using namespace std; int main() { CStack cs; //显示栈中元素 cout << "当前栈中元素有:" << endl; cs.display(); //添加元素入栈 for (int i = 0; i < 10; i++) cs.push(i*i); //显示栈中元素 cout << "当前栈中元素有:" << endl; cs.display(); //显示栈顶元素 cout << "栈顶元素为:" << endl; cout << cs.getTop() << endl; //栈顶元素出栈 cout << "栈顶元素出栈:"<< endl; cs.pop(); //重新打印栈元素 cout << "当前栈中元素有:" << endl; cs.display(); system("pause"); return 0; }
测试结果为:
队列
类似于数据结构栈,队列实现了一种先进先出(FIFO)的策略,在队列中,可以去掉的那个元素总是在集合中存在时间最长的那个。我们把作用于队列上的Insert操作称为入对EnQueue,把作用于队列上的Delete操作称为出队DeQueue。
本章讨论的队列也是用数组实现的,基本结构(CQueue.h)如下:
#ifndef _CQUEUE_H_ #define _CQUEUE_H_ #include <iostream> class CQueue{ public: CQueue(); ~CQueue(); bool empty() { return head == tail; } bool full() { return ((head == tail + 1) || (head == 0 && tail == maxSize-1)); } void enQueue(int x); void deQueue(); void display(); private: int *data; int head; int tail; //队列最大容量,最多存储maxSize-1个元素 const int maxSize = 10; }; #endif
如上所示,队列使用数据成员data这样一个动态数组存储元素,另外还包含的队头,队尾两个成员变量,在本程序实现的是一个循环队列,当head == tail时队列为空,当((head == tail + 1) || (head == 0 && tail == maxSize-1))队列为满,整个队列中最多存储了maxSize-1个元素。
类实现(CQueue.cpp)如下:
#include "CQueue.h" #include <iostream> using namespace std; CQueue::CQueue() { head = 0; tail = 0; data = new int[maxSize]; } CQueue::~CQueue() { delete data; } void CQueue::enQueue(int x) { if (full()) { cout << "队列已满" << endl; return; } data[tail] = x; if (tail == maxSize - 1) tail = 0; else tail += 1; } void CQueue::deQueue() { if (empty()) { cout << "队列空!" << endl; return; } cout << data[head] << endl; if (head == maxSize - 1) head = 0; else head += 1; } void CQueue::display() { if (empty()) { cout << "队列空!" << endl; return; } if (head > tail) { for (int i = head; i < maxSize-1; i++) cout << data[i] << "\t"; for (int j = 0; j < tail; j++) cout << data[j] << "\t"; } else{ for (int i = head; i < tail; i++) cout << data[i] << "\t"; } cout << endl; }
下面给出对以上自定义队列的测试程序(main.cpp)与测试结果:
#include "CQueue.h" #include <iostream> #include <cstdlib> using namespace std; int main() { CQueue cq; cout << "此时队的状态是:" << endl; cq.display(); for (int i = 0; i < 9; i++) cq.enQueue(i + 1); //显示队列中所有元素 cout << "显示队中所有元素" << endl; cq.display(); //再次入队一个元素 cout << "元素11入队!"; cq.enQueue(11); //队头依次出队 cout << "队头元素:" << endl; cq.deQueue(); cout << "队头元素:" << endl; cq.deQueue(); cout << "队头元素:" << endl; cq.deQueue(); //此时入队新元素 cout << "元素11入队!"<<endl; cq.enQueue(11); cout << "元素12入队!"<<endl; cq.enQueue(12); //再次显示队列中所有元素 cout << "显示队中所有元素" << endl; cq.display(); system("pause"); return 0; }
测试结果:
双向链表
在链表这种数据结构中,各个对象按照线性顺序排序。链表与数组不同,数组的线性顺序是由数组下标决定的,而链表中的顺序是由各个对象的指针决定的。对于本节讨论的双向链表,定义结构(CList.h)如下:
#ifndef _CLIST_H_ #define _CLIST_H_ #include <iostream> //双向链表结构体 typedef struct Node{ Node *prev; Node *next; int key; Node(int x) :prev(NULL), next(NULL), key(x){} }; class CList{ public: CList(); ~CList(); void Insert(int x); Node *Search(int value); void Delete(int x); void Display(); private: Node *head; }; #endif
如上所示,结构体Node定义了链表中结点的基本内容,包括prev,next两个指针来实现双向性,以及一个key存储结点元素。在CList类中定义了4中基本操作,本处对于增、查、删操作函数参数均为基本元素而不是链表结点(书中是以结点作为参数的,本处认为以元素值作为参数封装性更好)。
类实现(CList.cpp)如下:
#include "CList.h" #include <iostream> #include <cstdlib> using namespace std; CList::CList() { head = NULL; } CList::~CList() { delete head; } void CList::Insert(int x) { //新建一个结点,其值为x Node *node = new Node(x); node->next = head; if (head != NULL) { head->prev = node; } head = node; head->prev = NULL; } Node * CList::Search(int value) { Node *node = head; while (node != NULL && node->key != value) { node = node->next; } //如果找到相应结点 if (node) return node; else return NULL; } //删除值为x的结点 void CList::Delete(int x) { if (head == NULL) { std::cout << "链表为空!" << endl; return; } Node *node = Search(x); if (node) { if (node->prev != NULL) node->prev->next = node->next; else head = node->next; if (node->next != NULL) node->next->prev = node->prev; delete node; return; } else{ std::cout << "链表中无值为"<<x<<"的元素!" << endl; return; } } void CList::Display() { if (head == NULL) { std::cout << "链表为空!" << std::endl; return; } Node *node = head; while (node) { cout << node->key << "\t"; node = node->next; } cout << endl; }
代码说明不再赘述,下面给出自定义双向链表的测试程序(main.cpp)以及测试结果:
#include "CList.h" #include <iostream> #include <cstdlib> using namespace std; int main() { CList list; //打印链表 list.Display(); //向链表插入元素 for (int i = 0; i < 10; i++) list.Insert(i*i); cout << "打印链表:" << endl; list.Display(); //查找元素为9的结点 Node *node = list.Search(9); cout << "查找元素为9的结点" << node->key << endl; //删除元素为10的结点 list.Delete(10); cout << "打印链表:" << endl; list.Display(); //删除元素为36的结点 list.Delete(36); cout << "打印链表:" << endl; list.Display(); system("pause"); return 0; }
测试结果:
带哨兵的循环双向链表
我们在处理边界条件时为了方便而且减少错误,经常使用哨兵(Sentinel),它是一个哑对象,可以简化边界条件。此处,在链表的实现中实现哨兵,不仅可以减少因边界处理不当而引起的指针异常,还可以实现循环的双向链表。基本操作与上类似,下面给出具体实现:数据结构(SList.h)如下:
#ifndef _SLIST_H_ #define _SLIST_H_ #include <iostream> /** * 带哨兵的环形双向链表结构体 */ typedef struct SNode{ SNode *prev; SNode *next; int key; SNode(int x) :prev(NULL), next(NULL), key(x){} }; class SList{ public: SList(); ~SList(); void Insert(int x); SNode *Search(int value); void Delete(int x); void Display(); private: SNode *nil; }; #endif
类实现(SList.cpp)如下:
#include "SList.h" #include <iostream> using namespace std; SList::SList() { nil = new SNode(0); nil->prev = nil; nil->next = nil; } SList::~SList() { delete nil; } void SList::Insert(int x) { //新建一个结点,其值为x SNode *node = new SNode(x); node->next = nil->next; nil->next->prev = node; nil->next = node; node->prev = nil; } SNode * SList::Search(int value) { SNode *node = nil->next; while (node != nil && node->key != value) { node = node->next; } //如果找到相应结点 if (node != nil) return node; else return NULL; } //删除值为x的结点 void SList::Delete(int x) { if (nil->next == nil) { std::cout << "链表为空!" << endl; return; } SNode *node = Search(x); if (node) { node->prev->next = node->next; node->next->prev = node->prev; delete node; return; } else{ std::cout << "链表中无值为" << x << "的元素!" << endl; return; } } void SList::Display() { if (nil == nil) { std::cout << "链表为空!" << std::endl; return; } SNode *node = nil->next; while (node->next != nil) { cout << node->key << "\t"; node = node->next; } cout << endl; }
下面给出测试程序(main.cpp)和测试结果:
#include "SList.h" #include <iostream> #include <cstdlib> using namespace std; int main() { SList list; //打印链表 list.Display(); //向链表插入元素 for (int i = 0; i < 10; i++) list.Insert(i*i); cout << "打印链表:" << endl; list.Display(); //查找元素为9的结点 SNode *node = list.Search(9); cout << "查找元素为9的结点" << node->key << endl; //删除元素为10的结点 list.Delete(10); cout << "打印链表:" << endl; list.Display(); //删除元素为36的结点 list.Delete(36); cout << "打印链表:" << endl; list.Display(); system("pause"); return 0; }
测试结果:
相关文章推荐
- java数据结构和算法------顺序查找
- 数据结构基础 之 二叉搜索树的思想与实现
- java数据结构和算法------希尔排序
- 线段树详解(单点更新与成段更新\区间更新操作)
- 关于数据结构的10个面试题(c语言实现)
- java数据结构和算法------堆排序
- Scala 的数据结构
- 数据结构和算法系列 - FP-Tree算法的实现
- 《数据结构与算法分析c++描述》读书笔记五——优先队列(堆)
- Redis 数据结构之简单动态字符串SDS
- 算法与数据结构八日谈之六——数据结构专题(uncompleted)
- 开放《数据结构》专栏的代码
- 十五分钟介绍 Redis数据结构
- PAT《数据结构学习与实验指导》实验项目集 2-05
- 大话数据结构之四(串)
- 数据结构基础 之 树与二叉树 各类操作、思想与实现
- 大话数据结构之三(栈和队列)
- 算法与数据结构八日谈之五——数学相关
- 数据结构--堆的实现(上)
- Redis 数据结构使用场景