数据结构
一、数据结构的基本概念
1.逻辑结构
1)集合结构(集):结构中的元素除了同属一个集之外,没有任何联系。
2)线性结构(表):结构中的元素具有一对一的前后关系。
3)树型结构(树):结构中的元素具有一对多的父子关系。
4)网状结构(图):结构中的元素具有多对多的交叉映射关系。
2.物理结构
1)顺序结构(数组):结构中的元素存放在一段连续的地址空间中。随机访问方便,空间利用率低,插入删除不便。
2)链式结构(链式):结构中的元素存放在彼此独立的地址空间中,每个独立的地址空间被称为节点,节点除了保存数据以外,还保存另外一个或几个相关节点的地址。空间利用率高,插入删除方便,随机访问不便。
3.逻辑结构和物理结构的关系
表 树 图
顺序 数组 顺序树 复
链式 链表 链式树 合
二、数据结构的基本运算
1.创建与销毁
2.插入与删除
3.获取与修改
4.排序与查找
三、堆栈
1.基本特征:后进先出
2.基本操作:压入(push),弹出(pop)
3.实现要点:初始化空间,栈顶指针,判空判满。
1 #include <iostream> 2 using namespace std; 3 // 基于顺序表的堆栈 4 class Stack { 5 public: 6 // 构造过程中分配内存 7 Stack (size_t size = 10) : 8 m_array (new int[size]), m_size (size), 9 m_top (0) {} 10 // 析构过程中释放内存 11 ~Stack (void) { 12 if (m_array) { 13 delete[] m_array; 14 m_array = 0; 15 } 16 } 17 // 压入 18 void push (int data) { 19 if (full ()) 20 throw OverFlow (); 21 m_array[m_top++] = data; 22 } 23 // 弹出 24 int pop (void) { 25 if (empty ()) 26 throw UnderFlow (); 27 return m_array[--m_top]; 28 } 29 // 判满 30 bool full (void) const { 31 return m_top >= m_size; 32 } 33 // 判空 34 bool empty (void) const { 35 return ! m_top; 36 } 37 private: 38 // 上溢异常 39 class OverFlow : public exception { 40 const char* what (void) const throw () { 41 return "堆栈上溢!"; 42 } 43 }; 44 // 下溢异常 45 class UnderFlow : public exception { 46 const char* what (void) const throw () { 47 return "堆栈下溢!"; 48 } 49 }; 50 int* m_array; // 数组 51 size_t m_size; // 容量 52 size_t m_top; // 栈顶 53 }; 54 void printb (unsigned int numb, int base) { 55 Stack stack (256); 56 do { 57 stack.push (numb % base); 58 } while (numb /= base); 59 while (! stack.empty ()) { 60 int digit = stack.pop (); 61 if (digit < 10) 62 cout << digit; 63 else 64 cout << char (digit - 10 + 'A'); 65 } 66 cout << endl; 67 } 68 int main (void) { 69 try { 70 Stack stack; 71 for (int i = 0; ! stack.full (); ++i) 72 stack.push (i); 73 // stack.push (0); 74 while (! stack.empty ()) 75 cout << stack.pop () << endl; 76 // stack.pop (); 77 } 78 catch (exception& ex) { 79 cout << ex.what () << endl; 80 return -1; 81 } 82 cout << "输入一个整数:" << flush; 83 int numb; 84 cin >> numb; 85 cout << "您想看几进制:" << flush; 86 int base; 87 cin >> base; 88 cout << "结果:"; 89 printb (numb, base); 90 return 0; 91 }
1 #include <iostream> 2 using namespace std; 3 // 基于链式表的堆栈 4 class Stack { 5 public: 6 // 构造过程中初始化为空堆栈 7 Stack (void) : m_top (NULL) {} 8 // 析构过程中销毁剩余的节点 9 ~Stack (void) { 10 for (Node* next; m_top; m_top = next) { 11 next = m_top->m_next; 12 delete m_top; 13 } 14 } 15 // 压入 16 void push (int data) { 17 /* 18 Node* node = new Node; 19 node->m_data = data; 20 node->m_next = m_top; 21 m_top = node;*/ 22 m_top = new Node (data, m_top); 23 } 24 // 弹出 25 int pop (void) { 26 if (empty ()) 27 throw UnderFlow (); 28 int data = m_top->m_data; 29 Node* next = m_top->m_next; 30 delete m_top; 31 m_top = next; 32 return data; 33 } 34 // 判空 35 bool empty (void) const { 36 return ! m_top; 37 } 38 private: 39 // 下溢异常 40 class UnderFlow : public exception { 41 const char* what (void) const throw () { 42 return "堆栈下溢!"; 43 } 44 }; 45 // 节点 46 class Node { 47 public: 48 Node (int data = 0, Node* next = NULL) : 49 m_data (data), m_next (next) {} 50 int m_data; // 数据 51 Node* m_next; // 后指针 52 }; 53 Node* m_top; // 栈顶 54 }; 55 int main (void) { 56 try { 57 Stack stack; 58 for (int i = 0; i < 10; ++i) 59 stack.push (i); 60 while (! stack.empty ()) 61 cout << stack.pop () << endl; 62 // stack.pop (); 63 } 64 catch (exception& ex) { 65 cout << ex.what () << endl; 66 return -1; 67 } 68 return 0; 69 }
四、队列
1.基本特征:先进先出,FIFO
2.基本操作:压入(push)、弹出(pop)
3.实现要点:初始化空间,从前端(front)弹出,从后端(rear)压入,循环使用,判空判满
1 #include <iostream> 2 using namespace std; 3 // 基于顺序表的队列 4 class Queue { 5 public: 6 // 构造过程中分配内存 7 Queue (size_t size = 5) : 8 m_array (new int[size]), m_size (size), 9 m_rear (0), m_front (0), m_count (0) {} 10 // 析构过程中释放内存 11 ~Queue (void) { 12 if (m_array) { 13 delete[] m_array; 14 m_array = NULL; 15 } 16 } 17 // 压入 18 void push (int data) { 19 if (full ()) 20 throw OverFlow (); 21 if (m_rear >= m_size) 22 m_rear = 0; 23 ++m_count; 24 m_array[m_rear++] = data; 25 } 26 // 弹出 27 int pop (void) { 28 if (empty ()) 29 throw UnderFlow (); 30 if (m_front >= m_size) 31 m_front = 0; 32 --m_count; 33 return m_array[m_front++]; 34 } 35 // 判空 36 bool empty (void) const { 37 return ! m_count; 38 } 39 // 判满 40 bool full (void) const { 41 return m_count == m_size; 42 } 43 private: 44 // 上溢异常 45 class OverFlow : public exception { 46 const char* what (void) const throw () { 47 return "队列上溢!"; 48 } 49 }; 50 // 下溢异常 51 class UnderFlow : public exception { 52 const char* what (void) const throw () { 53 return "队列下溢!"; 54 } 55 }; 56 int* m_array; // 数组 57 size_t m_size; // 容量 58 size_t m_rear; // 后端 59 size_t m_front; // 前端 60 size_t m_count; // 计数 61 }; 62 int main (void) { 63 try { 64 Queue queue; 65 queue.push (10); 66 queue.push (20); 67 queue.push (30); 68 queue.push (40); 69 queue.push (50); 70 // queue.push (60); 71 cout << queue.pop () << endl; // 10 72 queue.push (60); 73 cout << queue.pop () << endl; // 20 74 queue.push (70); 75 // queue.push (80); 76 cout << queue.pop () << endl; // 30 77 cout << queue.pop () << endl; // 40 78 cout << queue.pop () << endl; // 50 79 cout << queue.pop () << endl; // 60 80 cout << queue.pop () << endl; // 70 81 // queue.pop (); 82 } 83 catch (exception& ex) { 84 cout << ex.what () << endl; 85 return -1; 86 } 87 return 0; 88 }
1 #include <iostream> 2 using namespace std; 3 // 基于链式表的队列 4 class Queue { 5 public: 6 // 在构造过程中初始化为空队列 7 Queue (void) : m_rear (NULL), m_front (NULL) {} 8 // 在析构过程中销毁剩余的节点 9 ~Queue (void) { 10 for (Node* next; m_front; m_front = next) { 11 next = m_front->m_next; 12 delete m_front; 13 } 14 } 15 // 压入 16 void push (int data) { 17 Node* node = new Node (data); 18 if (m_rear) 19 m_rear->m_next = node; 20 else 21 m_front = node; 22 m_rear = node; 23 } 24 // 弹出 25 int pop (void) { 26 if (empty ()) 27 throw UnderFlow (); 28 int data = m_front->m_data; 29 Node* next = m_front->m_next; 30 delete m_front; 31 if (! (m_front = next)) 32 m_rear = NULL; 33 return data; 34 } 35 // 判空 36 bool empty (void) const { 37 return ! m_front && ! m_rear; 38 } 39 private: 40 // 下溢异常 41 class UnderFlow : public exception { 42 const char* what (void) const throw () { 43 return "队列下溢!"; 44 } 45 }; 46 // 节点 47 class Node { 48 public: 49 Node (int data = 0, Node* next = NULL) : 50 m_data (data), m_next (next) {} 51 int m_data; // 数据 52 Node* m_next; // 后指针 53 }; 54 Node* m_rear; // 后端 55 Node* m_front; // 前端 56 }; 57 int main (void) { 58 try { 59 Queue queue; 60 for (int i = 0; i < 10; ++i) 61 queue.push (i); 62 while (! queue.empty ()) 63 cout << queue.pop () << endl; 64 }Node* 65 catch (exception& ex) { 66 cout << ex.what () << endl; 67 return -1; 68 } 69 return 0; 70 }
思考:用堆栈实现队列,俗称"适配器"。
1 /* 2 * 文件名: lstack.h 3 */ 4 #ifndef _LSTACK_H 5 #define _LSTACK_H 6 #include <stdexcept> 7 using namespace std; 8 // 基于链式表的堆栈 9 class Stack { 10 public: 11 // 构造过程中初始化为空堆栈 12 Stack (void) : m_top (NULL) {} 13 // 析构过程中销毁剩余的节点 14 ~Stack (void) { 15 for (Node* next; m_top; m_top = next) { 16 next = m_top->m_next; 17 delete m_top; 18 } 19 } 20 // 压入 21 void push (int data) { 22 /* 23 Node* node = new Node; 24 node->m_data = data; 25 node->m_next = m_top; 26 m_top = node;*/ 27 m_top = new Node (data, m_top); 28 } 29 // 弹出 30 int pop (void) { 31 if (empty ()) 32 throw UnderFlow (); 33 int data = m_top->m_data; 34 Node* next = m_top->m_next; 35 delete m_top; 36 m_top = next; 37 return data; 38 } 39 // 判空 40 bool empty (void) const { 41 return ! m_top; 42 } 43 private: 44 // 下溢异常 45 class UnderFlow : public exception { 46 const char* what (void) const throw () { 47 return "堆栈下溢!"; 48 } 49 }; 50 // 节点 51 class Node { 52 public: 53 Node (int data = 0, Node* next = NULL) : 54 m_data (data), m_next (next) {} 55 int m_data; // 数据 56 Node* m_next; // 后指针 57 }; 58 Node* m_top; // 栈顶 59 }; 60 #endif // _LSTACK_H
1 #include <iostream> 2 #include "lstack.h" 3 using namespace std; 4 // 基于堆栈的队列 5 class Queue { 6 public: 7 // 压入 8 void push (int data) { 9 m_i.push (data); 10 } 11 // 弹出 12 int pop (void) { 13 if (m_o.empty ()) { 14 if (m_i.empty ()) 15 throw underflow_error("队列下溢!"); 16 while (! m_i.empty ()) 17 m_o.push (m_i.pop ()); 18 } 19 return m_o.pop (); 20 } 21 // 判空 22 bool empty (void) const { 23 return m_i.empty () && m_o.empty (); 24 } 25 private: 26 Stack m_i; // 输入栈 27 Stack m_o; // 输出栈 28 }; 29 int main (void) { 30 try { 31 Queue queue; 32 for (int i = 0; i < 10; ++i) 33 queue.push (i); 34 cout << queue.pop () << endl; // 0 35 cout << queue.pop () << endl; // 1 36 cout << queue.pop () << endl; // 2 37 cout << queue.pop () << endl; // 3 38 cout << queue.pop () << endl; // 4 39 queue.push (10); 40 queue.push (11); 41 queue.push (12); 42 while (! queue.empty ()) 43 cout << queue.pop () << endl; 44 } 45 catch (exception& ex) { 46 cout << ex.what () << endl; 47 return -1; 48 } 49 return 0; 50 }
五、链表
1.基本特征:内存中不连续的节点序列,彼此之间通过指针相互关联,前指针(prev)指向前节点,后指针(next)指向后节点。
2.基本操作:追加、插入、删除、遍历
1 #include <iostream> 2 #include <stdexcept> 3 using namespace std; 4 // 双向线性链表 5 class List { 6 public: 7 // 构造过程中初始化为空链表 8 List (void) : m_head (NULL), m_tail (NULL) {} 9 // 析构过程中销毁剩余的节点 10 ~List (void) { 11 for (Node* next; m_head; m_head = next) { 12 next = m_head->m_next; 13 delete m_head; 14 } 15 } 16 // 追加 17 void append (int data) { 18 m_tail = new Node (data, m_tail); 19 if (m_tail->m_prev) 20 m_tail->m_prev->m_next = m_tail; 21 else 22 m_head = m_tail; 23 } 24 // 插入 25 void insert (size_t pos, int data) { 26 for (Node* find = m_head; find; 27 find = find->m_next) 28 if (pos-- == 0) { 29 Node* node = new Node (data, 30 find->m_prev, find); 31 if (node->m_prev) 32 node->m_prev->m_next = node; 33 else 34 m_head = node; 35 node->m_next->m_prev = node; 36 return; 37 } 38 throw out_of_range ("链表越界!"); 39 } 40 // 删除 41 void erase (size_t pos) { 42 for (Node* find = m_head; find; 43 find = find->m_next) 44 if (pos-- == 0) { 45 if (find->m_prev) 46 find->m_prev->m_next = 47 find->m_next; 48 else 49 m_head = find->m_next; 50 if (find->m_next) 51 find->m_next->m_prev = 52 find->m_prev; 53 else 54 m_tail = find->m_prev; 55 delete find; 56 return; 57 } 58 throw out_of_range ("链表越界!"); 59 } 60 // 正向遍历 61 void forward (void) const { 62 for (Node* node = m_head; node; 63 node = node->m_next) 64 cout << node->m_data << ' '; 65 cout << endl; 66 } 67 // 反向遍历 68 void backward (void) const { 69 for (Node* node = m_tail; node; 70 node = node->m_prev) 71 cout << node->m_data << ' '; 72 cout << endl; 73 } 74 // 下标访问 75 int& operator[] (size_t index) { 76 for (Node* find = m_head; find; 77 find = find->m_next) 78 if (index-- == 0) 79 return find->m_data; 80 throw out_of_range ("链表越界!"); 81 } 82 const int& operator[] (size_t index) const { 83 return const_cast<List&> (*this) [index]; 84 } 85 private: 86 // 节点 87 class Node { 88 public: 89 Node (int data = 0, Node* prev = NULL, 90 Node* next = NULL) : m_data (data), 91 m_prev (prev), m_next (next) {} 92 int m_data; // 数据 93 Node* m_prev; // 前指针 94 Node* m_next; // 后指针 95 }; 96 Node* m_head; // 头指针 97 Node* m_tail; // 尾指针 98 }; 99 int main (void) { 100 try { 101 List list; 102 list.append (10); 103 list.append (30); 104 list.append (50); 105 list.append (60); 106 list.append (80); 107 list.insert (1, 20); 108 list.insert (3, 40); 109 list.insert (6, 70); 110 list.forward (); 111 list.backward (); 112 list.erase (5); 113 list.erase (5); 114 list.erase (5); 115 list.forward (); 116 for (size_t i = 0; i < 5; ++i) 117 ++list[i]; 118 const List& cr = list; 119 for (size_t i = 0; i < 5; ++i) 120 cout << /*++*/cr[i] << ' '; 121 cout << endl; 122 } 123 catch (exception& ex) { 124 cout << ex.what () << endl; 125 return -1; 126 } 127 return 0; 128 }
1 // 练习:实现一个单向线性链表类 2 // 1.建立、测长、正反向打印 3 // 2.逆转 4 // 3.获取中间节点值,单次遍历 5 // 4.有序链表的插入和删除 6 #include <iostream> 7 #include <stdexcept> 8 using namespace std; 9 class List { 10 public: 11 List (void) : m_head (NULL), m_tail (NULL) {} 12 ~List (void) { 13 for (Node* next; m_head; m_head = next) { 14 next = m_head->m_next; 15 delete m_head; 16 } 17 } 18 void append (int data) { 19 Node* node = new Node (data); 20 if (m_tail) 21 m_tail->m_next = node; 22 else 23 m_head = node; 24 m_tail = node; 25 } 26 size_t size (void) const { 27 size_t cn = 0; 28 for (Node* node = m_head; node; 29 node = node->m_next) 30 ++cn; 31 return cn; 32 } 33 void print (void) const { 34 for (Node* node = m_head; node; 35 node = node->m_next) 36 cout << node->m_data << ' '; 37 cout << endl; 38 } 39 void rprint (void) const { 40 rprint (m_head); 41 cout << endl; 42 } 43 /* 44 void reverse (void) { 45 reverse (m_head); 46 swap (m_head, m_tail); 47 } 48 */ 49 void reverse (void) { 50 if (m_head != m_tail) { 51 Node* p1 = m_tail = m_head; 52 Node* p2 = p1->m_next; 53 Node* p3 = p2->m_next; 54 for (p1->m_next=NULL;p3;p3=p3->m_next) { 55 p2->m_next = p1; 56 p1 = p2; 57 p2 = p3; 58 } 59 (m_head = p2)->m_next = p1; 60 } 61 } 62 int middle (void) const { 63 if (! m_head || ! m_tail) 64 throw underflow_error ("链表下溢!"); 65 if (m_head == m_tail) 66 return m_head->m_data; 67 Node* mid = m_head; 68 for (Node* node = m_head; 69 node->m_next && node->m_next->m_next; 70 node = node->m_next->m_next) 71 mid = mid->m_next; 72 return mid->m_data; 73 } 74 // 插入data,仍然保持有序 75 void insert (int data) { 76 } 77 // 删除所有的data 78 void remove (int data) { 79 } 80 private: 81 class Node { 82 public: 83 Node (int data = 0, Node* next = NULL) : 84 m_data (data), m_next (next) {} 85 int m_data; 86 Node* m_next; 87 }; 88 void rprint (Node* head) const { 89 if (head) { 90 rprint (head->m_next); 91 cout << head->m_data << ' '; 92 } 93 } 94 void reverse (Node* head) { 95 if (head && head->m_next) { 96 reverse (head->m_next); 97 head->m_next->m_next = head; 98 head->m_next = NULL; 99 } 100 } 101 Node* m_head; 102 Node* m_tail; 103 }; 104 int main (void) { 105 List list; 106 for (int i = 0; i < 11; ++i) 107 list.append (i); 108 cout << list.size () << endl; 109 list.print (); 110 list.rprint (); 111 list.reverse (); 112 list.print (); 113 cout << list.middle () << endl; 114 return 0; 115 }
六、二叉树
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
1 #include <iostream> 2 using namespace std; 3 // 有序二叉树(二叉搜索树) 4 class Tree { 5 public: 6 // 构造过程中初始化为空树 7 Tree (void) : m_root (NULL), m_size (0) {} 8 // 析构过程中销毁剩余节点 9 ~Tree (void) { 10 clear (); 11 } 12 // 插入数据 13 void insert (int data) { 14 insert (new Node (data), m_root); 15 ++m_size; 16 } 17 // 删除第一个匹配数据,不存在返回false 18 bool erase (int data) { 19 Node*& node = find (data, m_root); 20 if (node) { 21 // 左插右 22 insert (node->m_left, node->m_right); 23 Node* temp = node; 24 // 右提升 25 node = node->m_right; 26 delete temp; 27 --m_size; 28 return true; 29 } 30 return false; 31 } 32 // 删除所有匹配数据 33 void remove (int data) { 34 while (erase (data)); 35 } 36 // 清空树 37 void clear (void) { 38 clear (m_root); 39 m_size = 0; 40 } 41 // 将所有的_old替换为_new 42 void update (int _old, int _new) { 43 while (erase (_old)) 44 insert (_new); 45 } 46 // 判断data是否存在 47 bool find (int data) { 48 return find (data, m_root) != NULL; 49 } 50 // 中序遍历 51 void travel (void) { 52 travel (m_root); 53 cout << endl; 54 } 55 // 获取大小 56 size_t size (void) { 57 return m_size; 58 } 59 // 获取树高 60 size_t height (void) { 61 return height (m_root); 62 } 63 private: 64 // 节点 65 class Node { 66 public: 67 Node (int data) : m_data (data), 68 m_left (NULL), m_right (NULL) {} 69 int m_data; // 数据 70 Node* m_left; // 左树 71 Node* m_right; // 右树 72 }; 73 void insert (Node* node, Node*& tree) { 74 if (! tree) 75 tree = node; 76 else if (node) { 77 if (node->m_data < tree->m_data) 78 insert (node, tree->m_left); 79 else 80 insert (node, tree->m_right); 81 } 82 } 83 // 返回子树tree中值与data相匹配的节点的父节点中 84 // 指向该节点的成员变量的别名 85 Node*& find (int data, Node*& tree) { 86 if (! tree) 87 return tree; 88 else 89 if (data == tree->m_data) 90 return tree; 91 else 92 if (data < tree->m_data) 93 return find (data, tree->m_left); 94 else 95 return find (data, tree->m_right); 96 } 97 void clear (Node*& tree) { 98 if (tree) { 99 clear (tree->m_left); 100 clear (tree->m_right); 101 delete tree; 102 tree = NULL; 103 } 104 } 105 void travel (Node* tree) { 106 if (tree) { 107 travel (tree->m_left); 108 cout << tree->m_data << ' '; 109 travel (tree->m_right); 110 } 111 } 112 size_t height (Node* tree) { 113 if (tree) { 114 size_t lh = height (tree->m_left); 115 size_t rh = height (tree->m_right); 116 return (lh > rh ? lh : rh) + 1; 117 } 118 return 0; 119 } 120 Node* m_root; // 树根 121 size_t m_size; // 大小 122 }; 123 int main (void) { 124 Tree tree; 125 tree.insert (50); 126 tree.insert (70); 127 tree.insert (20); 128 tree.insert (60); 129 tree.insert (40); 130 tree.insert (30); 131 tree.insert (10); 132 tree.insert (90); 133 tree.insert (80); 134 tree.travel (); 135 cout << tree.size () << ' ' << tree.height () 136 << endl; 137 tree.erase (70); 138 tree.travel (); 139 tree.insert (70); 140 tree.insert (70); 141 tree.insert (70); 142 tree.travel (); 143 tree.remove (70); 144 tree.travel (); 145 tree.insert (40); 146 tree.insert (40); 147 tree.travel (); 148 tree.update (40, 69); 149 tree.travel (); 150 cout << boolalpha << tree.find (50) << endl; 151 cout << tree.find (55) << endl; 152 tree.clear (); 153 tree.travel (); 154 return 0; 155 }