您的位置:首页 > 编程语言 > C语言/C++

Standard C++ Episode 8

2015-08-21 04:21 537 查看
数据结构

一、数据结构的基本概念

1.逻辑结构

1)集合结构(集):结构中的元素除了同属一个集之外,没有任何联系。

2)线性结构(表):结构中的元素具有一对一的前后关系。

3)树型结构(树):结构中的元素具有一对多的父子关系。

4)网状结构(图):结构中的元素具有多对多的交叉映射关系。

2.物理结构

1)顺序结构(数组):结构中的元素存放在一段连续的地址空间中。随机访问方便,空间利用率低,插入删除不便。

2)链式结构(链式):结构中的元素存放在彼此独立的地址空间中,每个独立的地址空间被称为节点,节点除了保存数据以外,还保存另外一个或几个相关节点的地址。空间利用率高,插入删除方便,随机访问不便。

3.逻辑结构和物理结构的关系

表 树 图

顺序 数组 顺序树 复

链式 链表 链式树 合

二、数据结构的基本运算

1.创建与销毁

2.插入与删除

3.获取与修改

4.排序与查找

三、堆栈

1.基本特征:后进先出

2.基本操作:压入(push),弹出(pop)

3.实现要点:初始化空间,栈顶指针,判空判满。

#include <iostream>
using namespace std;
// 基于顺序表的堆栈
class Stack {
public:
// 构造过程中分配内存
Stack (size_t size = 10) :
m_array (new int[size]), m_size (size),
m_top (0) {}
// 析构过程中释放内存
~Stack (void) {
if (m_array) {
delete[] m_array;
m_array = 0;
}
}
// 压入
void push (int data) {
if (full ())
throw OverFlow ();
m_array[m_top++] = data;
}
// 弹出
int pop (void) {
if (empty ())
throw UnderFlow ();
return m_array[--m_top];
}
// 判满
bool full (void) const {
return m_top >= m_size;
}
// 判空
bool empty (void) const {
return ! m_top;
}
private:
// 上溢异常
class OverFlow : public exception {
const char* what (void) const throw () {
return "堆栈上溢!";
}
};
// 下溢异常
class UnderFlow : public exception {
const char* what (void) const throw () {
return "堆栈下溢!";
}
};
int* m_array; // 数组
size_t m_size; // 容量
size_t m_top; // 栈顶
};
void printb (unsigned int numb, int base) {
Stack stack (256);
do {
stack.push (numb % base);
}    while (numb /= base);
while (! stack.empty ()) {
int digit = stack.pop ();
if (digit < 10)
cout << digit;
else
cout << char (digit - 10 + 'A');
}
cout << endl;
}
int main (void) {
try {
Stack stack;
for (int i = 0; ! stack.full (); ++i)
stack.push (i);
//        stack.push (0);
while (! stack.empty ())
cout << stack.pop () << endl;
//        stack.pop ();
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
cout << "输入一个整数:" << flush;
int numb;
cin >> numb;
cout << "您想看几进制:" << flush;
int base;
cin >> base;
cout << "结果:";
printb (numb, base);
return 0;
}


#include <iostream>
using namespace std;
// 基于链式表的堆栈
class Stack {
public:
// 构造过程中初始化为空堆栈
Stack (void) : m_top (NULL) {}
// 析构过程中销毁剩余的节点
~Stack (void) {
for (Node* next; m_top; m_top = next) {
next = m_top->m_next;
delete m_top;
}
}
// 压入
void push (int data) {
/*
Node* node = new Node;
node->m_data = data;
node->m_next = m_top;
m_top = node;*/
m_top = new Node (data, m_top);
}
// 弹出
int pop (void) {
if (empty ())
throw UnderFlow ();
int data = m_top->m_data;
Node* next = m_top->m_next;
delete m_top;
m_top = next;
return data;
}
// 判空
bool empty (void) const {
return ! m_top;
}
private:
// 下溢异常
class UnderFlow : public exception {
const char* what (void) const throw () {
return "堆栈下溢!";
}
};
// 节点
class Node {
public:
Node (int data = 0, Node* next = NULL) :
m_data (data), m_next (next) {}
int m_data; // 数据
Node* m_next; // 后指针
};
Node* m_top; // 栈顶
};
int main (void) {
try {
Stack stack;
for (int i = 0; i < 10; ++i)
stack.push (i);
while (! stack.empty ())
cout << stack.pop () << endl;
//        stack.pop ();
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}


四、队列

1.基本特征:先进先出,FIFO

2.基本操作:压入(push)、弹出(pop)

3.实现要点:初始化空间,从前端(front)弹出,从后端(rear)压入,循环使用,判空判满

#include <iostream>
using namespace std;
// 基于顺序表的队列
class Queue {
public:
// 构造过程中分配内存
Queue (size_t size = 5) :
m_array (new int[size]), m_size (size),
m_rear (0), m_front (0), m_count (0) {}
// 析构过程中释放内存
~Queue (void) {
if (m_array) {
delete[] m_array;
m_array = NULL;
}
}
// 压入
void push (int data) {
if (full ())
throw OverFlow ();
if (m_rear >= m_size)
m_rear = 0;
++m_count;
m_array[m_rear++] = data;
}
// 弹出
int pop (void) {
if (empty ())
throw UnderFlow ();
if (m_front >= m_size)
m_front = 0;
--m_count;
return m_array[m_front++];
}
// 判空
bool empty (void) const {
return ! m_count;
}
// 判满
bool full (void) const {
return m_count == m_size;
}
private:
// 上溢异常
class OverFlow : public exception {
const char* what (void) const throw () {
return "队列上溢!";
}
};
// 下溢异常
class UnderFlow : public exception {
const char* what (void) const throw () {
return "队列下溢!";
}
};
int* m_array; // 数组
size_t m_size; // 容量
size_t m_rear; // 后端
size_t m_front; // 前端
size_t m_count; // 计数
};
int main (void) {
try {
Queue queue;
queue.push (10);
queue.push (20);
queue.push (30);
queue.push (40);
queue.push (50);
//        queue.push (60);
cout << queue.pop () << endl; // 10
queue.push (60);
cout << queue.pop () << endl; // 20
queue.push (70);
//        queue.push (80);
cout << queue.pop () << endl; // 30
cout << queue.pop () << endl; // 40
cout << queue.pop () << endl; // 50
cout << queue.pop () << endl; // 60
cout << queue.pop () << endl; // 70
//        queue.pop ();
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}


#include <iostream>
using namespace std;
// 基于链式表的队列
class Queue {
public:
// 在构造过程中初始化为空队列
Queue (void) : m_rear (NULL), m_front (NULL) {}
// 在析构过程中销毁剩余的节点
~Queue (void) {
for (Node* next; m_front; m_front = next) {
next = m_front->m_next;
delete m_front;
}
}
// 压入
void push (int data) {
Node* node = new Node (data);
if (m_rear)
m_rear->m_next = node;
else
m_front = node;
m_rear = node;
}
// 弹出
int pop (void) {
if (empty ())
throw UnderFlow ();
int data = m_front->m_data;
Node* next = m_front->m_next;
delete m_front;
if (! (m_front = next))
m_rear = NULL;
return data;
}
// 判空
bool empty (void) const {
return ! m_front && ! m_rear;
}
private:
// 下溢异常
class UnderFlow : public exception {
const char* what (void) const throw () {
return "队列下溢!";
}
};
// 节点
class Node {
public:
Node (int data = 0, Node* next = NULL) :
m_data (data), m_next (next) {}
int m_data; // 数据
Node* m_next; // 后指针
};
Node* m_rear; // 后端
Node* m_front; // 前端
};
int main (void) {
try {
Queue queue;
for (int i = 0; i < 10; ++i)
queue.push (i);
while (! queue.empty ())
cout << queue.pop () << endl;
}Node*
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}


思考:用堆栈实现队列,俗称"适配器"。

/*
* 文件名: lstack.h
*/
#ifndef _LSTACK_H
#define _LSTACK_H
#include <stdexcept>
using namespace std;
// 基于链式表的堆栈
class Stack {
public:
// 构造过程中初始化为空堆栈
Stack (void) : m_top (NULL) {}
// 析构过程中销毁剩余的节点
~Stack (void) {
for (Node* next; m_top; m_top = next) {
next = m_top->m_next;
delete m_top;
}
}
// 压入
void push (int data) {
/*
Node* node = new Node;
node->m_data = data;
node->m_next = m_top;
m_top = node;*/
m_top = new Node (data, m_top);
}
// 弹出
int pop (void) {
if (empty ())
throw UnderFlow ();
int data = m_top->m_data;
Node* next = m_top->m_next;
delete m_top;
m_top = next;
return data;
}
// 判空
bool empty (void) const {
return ! m_top;
}
private:
// 下溢异常
class UnderFlow : public exception {
const char* what (void) const throw () {
return "堆栈下溢!";
}
};
// 节点
class Node {
public:
Node (int data = 0, Node* next = NULL) :
m_data (data), m_next (next) {}
int m_data; // 数据
Node* m_next; // 后指针
};
Node* m_top; // 栈顶
};
#endif // _LSTACK_H


#include <iostream>
#include "lstack.h"
using namespace std;
// 基于堆栈的队列
class Queue {
public:
// 压入
void push (int data) {
m_i.push (data);
}
// 弹出
int pop (void) {
if (m_o.empty ()) {
if (m_i.empty ())
throw underflow_error("队列下溢!");
while (! m_i.empty ())
m_o.push (m_i.pop ());
}
return m_o.pop ();
}
// 判空
bool empty (void) const {
return m_i.empty () && m_o.empty ();
}
private:
Stack m_i; // 输入栈
Stack m_o; // 输出栈
};
int main (void) {
try {
Queue queue;
for (int i = 0; i < 10; ++i)
queue.push (i);
cout << queue.pop () << endl; // 0
cout << queue.pop () << endl; // 1
cout << queue.pop () << endl; // 2
cout << queue.pop () << endl; // 3
cout << queue.pop () << endl; // 4
queue.push (10);
queue.push (11);
queue.push (12);
while (! queue.empty ())
cout << queue.pop () << endl;
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}


五、链表

1.基本特征:内存中不连续的节点序列,彼此之间通过指针相互关联,前指针(prev)指向前节点,后指针(next)指向后节点。

2.基本操作:追加、插入、删除、遍历

#include <iostream>
#include <stdexcept>
using namespace std;
// 双向线性链表
class List {
public:
// 构造过程中初始化为空链表
List (void) : m_head (NULL), m_tail (NULL) {}
// 析构过程中销毁剩余的节点
~List (void) {
for (Node* next; m_head; m_head = next) {
next = m_head->m_next;
delete m_head;
}
}
// 追加
void append (int data) {
m_tail = new Node (data, m_tail);
if (m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
// 插入
void insert (size_t pos, int data) {
for (Node* find = m_head; find;
find = find->m_next)
if (pos-- == 0) {
Node* node = new Node (data,
find->m_prev, find);
if (node->m_prev)
node->m_prev->m_next = node;
else
m_head = node;
node->m_next->m_prev = node;
return;
}
throw out_of_range ("链表越界!");
}
// 删除
void erase (size_t pos) {
for (Node* find = m_head; find;
find = find->m_next)
if (pos-- == 0) {
if (find->m_prev)
find->m_prev->m_next =
find->m_next;
else
m_head = find->m_next;
if (find->m_next)
find->m_next->m_prev =
find->m_prev;
else
m_tail = find->m_prev;
delete find;
return;
}
throw out_of_range ("链表越界!");
}
// 正向遍历
void forward (void) const {
for (Node* node = m_head; node;
node = node->m_next)
cout << node->m_data << ' ';
cout << endl;
}
// 反向遍历
void backward (void) const {
for (Node* node = m_tail; node;
node = node->m_prev)
cout << node->m_data << ' ';
cout << endl;
}
// 下标访问
int& operator[] (size_t index) {
for (Node* find = m_head; find;
find = find->m_next)
if (index-- == 0)
return find->m_data;
throw out_of_range ("链表越界!");
}
const int& operator[] (size_t index) const {
return const_cast<List&> (*this) [index];
}
private:
// 节点
class Node {
public:
Node (int data = 0, Node* prev = NULL,
Node* next = NULL) : m_data (data),
m_prev (prev), m_next (next) {}
int m_data; // 数据
Node* m_prev; // 前指针
Node* m_next; // 后指针
};
Node* m_head; // 头指针
Node* m_tail; // 尾指针
};
int main (void) {
try {
List list;
list.append (10);
list.append (30);
list.append (50);
list.append (60);
list.append (80);
list.insert (1, 20);
list.insert (3, 40);
list.insert (6, 70);
list.forward ();
list.backward ();
list.erase (5);
list.erase (5);
list.erase (5);
list.forward ();
for (size_t i = 0; i < 5; ++i)
++list[i];
const List& cr = list;
for (size_t i = 0; i < 5; ++i)
cout << /*++*/cr[i] << ' ';
cout << endl;
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}


// 练习:实现一个单向线性链表类
// 1.建立、测长、正反向打印
// 2.逆转
// 3.获取中间节点值,单次遍历
// 4.有序链表的插入和删除
#include <iostream>
#include <stdexcept>
using namespace std;
class List {
public:
List (void) : m_head (NULL), m_tail (NULL) {}
~List (void) {
for (Node* next; m_head; m_head = next) {
next = m_head->m_next;
delete m_head;
}
}
void append (int data) {
Node* node = new Node (data);
if (m_tail)
m_tail->m_next = node;
else
m_head = node;
m_tail = node;
}
size_t size (void) const {
size_t cn = 0;
for (Node* node = m_head; node;
node = node->m_next)
++cn;
return cn;
}
void print (void) const {
for (Node* node = m_head; node;
node = node->m_next)
cout << node->m_data << ' ';
cout << endl;
}
void rprint (void) const {
rprint (m_head);
cout << endl;
}
/*
void reverse (void) {
reverse (m_head);
swap (m_head, m_tail);
}
*/
void reverse (void) {
if (m_head != m_tail) {
Node* p1 = m_tail = m_head;
Node* p2 = p1->m_next;
Node* p3 = p2->m_next;
for (p1->m_next=NULL;p3;p3=p3->m_next) {
p2->m_next = p1;
p1 = p2;
p2 = p3;
}
(m_head = p2)->m_next = p1;
}
}
int middle (void) const {
if (! m_head || ! m_tail)
throw underflow_error ("链表下溢!");
if (m_head == m_tail)
return m_head->m_data;
Node* mid = m_head;
for (Node* node = m_head;
node->m_next && node->m_next->m_next;
node = node->m_next->m_next)
mid = mid->m_next;
return mid->m_data;
}
// 插入data,仍然保持有序
void insert (int data) {
}
// 删除所有的data
void remove (int data) {
}
private:
class Node {
public:
Node (int data = 0, Node* next = NULL) :
m_data (data), m_next (next) {}
int m_data;
Node* m_next;
};
void rprint (Node* head) const {
if (head) {
rprint (head->m_next);
cout << head->m_data << ' ';
}
}
void reverse (Node* head) {
if (head && head->m_next) {
reverse (head->m_next);
head->m_next->m_next = head;
head->m_next = NULL;
}
}
Node* m_head;
Node* m_tail;
};
int main (void) {
List list;
for (int i = 0; i < 11; ++i)
list.append (i);
cout << list.size () << endl;
list.print ();
list.rprint ();
list.reverse ();
list.print ();
cout << list.middle () << endl;
return 0;
}


六、二叉树

1.基本特征

1)树型结构的最简模型,每个节点最多有两个子节点。

2)单根。除根节点外每个节点有且仅有一个父节点,整棵树只有一个根节点。

3)递归结构,用递归处理二叉树问题可以简化算法。

2.基本操作

1)生成

2)遍历

D-L-R:前序遍历

L-D-R:中序遍历

L-R-D:后序遍历

有序二叉树(二叉搜索树)

L<=D<=R

50 70 20 60 40 30 10 90 80

50

/ \

/-- --\

20| 70

/ \ / \

10 40 60 90

/ /

30 80

/

10

中序遍历:10 20 30 40 50 60 70 80 90

#include <iostream>
using namespace std;
// 有序二叉树(二叉搜索树)
class Tree {
public:
// 构造过程中初始化为空树
Tree (void) : m_root (NULL), m_size (0) {}
// 析构过程中销毁剩余节点
~Tree (void) {
clear ();
}
// 插入数据
void insert (int data) {
insert (new Node (data), m_root);
++m_size;
}
// 删除第一个匹配数据,不存在返回false
bool erase  (int data) {
Node*& node = find (data, m_root);
if (node) {
// 左插右
insert (node->m_left, node->m_right);
Node* temp = node;
// 右提升
node = node->m_right;
delete temp;
--m_size;
return true;
}
return false;
}
// 删除所有匹配数据
void remove (int data) {
while (erase (data));
}
// 清空树
void clear (void) {
clear (m_root);
m_size = 0;
}
// 将所有的_old替换为_new
void update (int _old, int _new) {
while (erase (_old))
insert (_new);
}
// 判断data是否存在
bool find (int data) {
return find (data, m_root) != NULL;
}
// 中序遍历
void travel (void) {
travel (m_root);
cout << endl;
}
// 获取大小
size_t size (void) {
return m_size;
}
// 获取树高
size_t height (void) {
return height (m_root);
}
private:
// 节点
class Node {
public:
Node (int data) : m_data (data),
m_left (NULL), m_right (NULL) {}
int m_data; // 数据
Node* m_left; // 左树
Node* m_right; // 右树
};
void insert (Node* node, Node*& tree) {
if (! tree)
tree = node;
else if (node) {
if (node->m_data < tree->m_data)
insert (node, tree->m_left);
else
insert (node, tree->m_right);
}
}
// 返回子树tree中值与data相匹配的节点的父节点中
// 指向该节点的成员变量的别名
Node*& find (int data, Node*& tree) {
if (! tree)
return tree;
else
if (data == tree->m_data)
return tree;
else
if (data < tree->m_data)
return find (data, tree->m_left);
else
return find (data, tree->m_right);
}
void clear (Node*& tree) {
if (tree) {
clear (tree->m_left);
clear (tree->m_right);
delete tree;
tree = NULL;
}
}
void travel (Node* tree) {
if (tree) {
travel (tree->m_left);
cout << tree->m_data << ' ';
travel (tree->m_right);
}
}
size_t height (Node* tree) {
if (tree) {
size_t lh = height (tree->m_left);
size_t rh = height (tree->m_right);
return (lh > rh ? lh : rh) + 1;
}
return 0;
}
Node* m_root; // 树根
size_t m_size; // 大小
};
int main (void) {
Tree tree;
tree.insert (50);
tree.insert (70);
tree.insert (20);
tree.insert (60);
tree.insert (40);
tree.insert (30);
tree.insert (10);
tree.insert (90);
tree.insert (80);
tree.travel ();
cout << tree.size () << ' ' << tree.height ()
<< endl;
tree.erase (70);
tree.travel ();
tree.insert (70);
tree.insert (70);
tree.insert (70);
tree.travel ();
tree.remove (70);
tree.travel ();
tree.insert (40);
tree.insert (40);
tree.travel ();
tree.update (40, 69);
tree.travel ();
cout << boolalpha << tree.find (50) << endl;
cout << tree.find (55) << endl;
tree.clear ();
tree.travel ();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: