数据结构
|总字数:6.4k|阅读时长:29分钟|浏览量:|
数据结构
引入
对于程序员来说,数据结构是一门非常重要的科目,但是也是一门比较难以掌握的科目,这里记录了自己在大学课程中的一些实践代码,方便以后回来看看自己写的数据结构有多烂……
线性表
顺序结构
线性表的顺序存储,C++代码实现如下
SeqlList.h,如果一个类使用了模板的话,不能将实现与定义拆分成两个文件,这个问题我卡了很久很久~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| #pragma once #include <iostream> using namespace std;
const int MaxSize = 200;
template <typename DataType = int> class SeqList { public: SeqList(); SeqList(DataType a[], int n); ~SeqList(); int Length(); DataType Get(int i); int Locate(DataType x); void Insert(int i, DataType x); DataType Delete(int i); int Empty(); void PrintList(); private: DataType data[MaxSize]; int length; };
template <typename DataType> SeqList<DataType>::SeqList() { this->length = 0; };
template <typename DataType> SeqList<DataType>::SeqList(DataType a[], int n) { if (n > MaxSize) throw "参数非法"; for (int i = 0; i < n; i++) { this->data[i] = a[i]; } this->length = n; }
template <typename DataType> SeqList<DataType>::~SeqList() { cout << "被销毁了" << endl; }
template <typename DataType> int SeqList<DataType>::Length() { return this->length; }
template <typename DataType> DataType SeqList<DataType>::Get(int i) { if (i < 1 || i > this->length) { throw "位置不存在"; } return this->data[i - 1]; }
template <typename DataType> int SeqList<DataType>::Locate(DataType x) { for (int i = 0; i < length; i++) { if (this->data[i] == x) { return i + 1; } } return 0; }
template <typename DataType> void SeqList<DataType>::Insert(int i, DataType x) { if (length >= MaxSize) throw "已满"; if (i < 1 || i > length + 1) throw "位置错误"; for (int j = length; j >= i - 1; j--) { this->data[j + 1] = this->data[j]; } this->data[i - 1] = x; this->length++; }
template <typename DataType> DataType SeqList<DataType>::Delete(int i) { if (i < 1 || i > length) throw "位置错误";
DataType del = this->Get(i);
for (int j = i-1; j < length - 1; j++) { this->data[j] = this->data[j + 1]; }
this->length--;
return del; }
template <typename DataType> int SeqList<DataType>::Empty() { return this->length ? 0 : 1; }
template <typename DataType> void SeqList<DataType>::PrintList() { if (this->Empty()) { cout << "{}" << endl; return; }
int i = 0;
cout << "{"; for (; i < length - 1; i++) { cout << this->data[i] << ","; } cout << this->data[i] << "}" << endl; }
|
Main.cpp,做了个菜单,自我感觉良好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| #include <iostream> #include "SeqList.h"
using namespace std;
template <typename DataType = int> void Menu(int choose, SeqList<>* list);
void Clear();
int main() { SeqList<> list; int choose = -1;
while (choose) { cout << "--------------------------------" << endl; cout << "元素[" << list.Length() << "]个|最大容量[" << MaxSize << "]个|顺序表状态"; list.PrintList(); cout << "1、插入一个数字" << endl; cout << "2、指定位置插入一个数字" << endl; cout << "3、获取某个数的具体位置" << endl; cout << "4、获取一个具体位置的数" << endl; cout << "5、删除一个指定位置的数" << endl; cout << "0、退出演示" << endl; cout << "请输入对应服务编号:"; cin >> choose; try { Menu(choose, &list); } catch (const char * e) { cout << "出错啦,错误消息:" << e << endl; } cout << endl << "--------------------------------" << endl; } }
template <typename DataType = int> void Menu(int choose, SeqList<>* list) { int in_1 = 0, in_2 = 0, temp_1 = 0; switch (choose) { case 1: cout << "请输入要插入的数字:"; cin >> in_1; list->Insert(list->Length() + 1, in_1); break; case 2: cout << "请输入指定位置与要插入的数字:"; cin >> in_1 >> in_2; list->Insert(in_1, in_2); break; case 3: cout << "请输入要查询的数:"; cin >> in_1; temp_1 = list->Locate(in_1); if (temp_1) { cout << "所查数第一次出现的位置是:" << temp_1 << endl; } else { cout << "没有查到哦~" << endl; } break; case 4: cout << "请输入要查找的位置:"; cin >> in_1; temp_1 = list->Get(in_1); cout << "所在位置的数是:" << temp_1 << endl; break; case 5: cout << "请输入要删除的位置:"; cin >> in_1; list->Delete(in_1); break; case 0: cout << "感谢体验,再见~" << endl; break; default: cout << "输入有误" << endl; } }
void Clear() { cout << "\x1B[2J\x1B[H"; }
|
运行效果
单链表
单链表有头插法和尾插法的说法,案例代码具体体现在链表的有参初始工作中
LinkList.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
| #pragma once #include <iostream> using namespace std;
template <typename DataType = int> struct Node { DataType data; Node<DataType>* next; };
template <typename DataType = int> class LinkList { public: LinkList(); LinkList(DataType a[], int n); ~LinkList(); int Length(); DataType Get(int i); int Locate(DataType x); void Insert(int i, DataType x); DataType Delete(int i); int Empty(); void PrintList(); private: Node<DataType>* header; };
template <typename DataType> LinkList<DataType>::LinkList() { this->header = new Node<DataType>; this->header->next = nullptr; }
template <typename DataType> LinkList<DataType>::LinkList(DataType a[], int n) { this->header = new Node<DataType>; this->header->next = nullptr; Node<DataType>* temp = nullptr; for (int i = 0; i < n; i++) { temp = this->header->next; this->header->next = new Node<DataType>; this->header->next->data = a[i]; this->header->next->next = temp; } }
template <typename DataType> LinkList<DataType>::~LinkList() { cout << "被销毁了" << endl; }
template <typename DataType> int LinkList<DataType>::Length() { int cnt = 0; Node<DataType>* temp = this->header; while (temp->next != nullptr) { temp = temp->next; cnt++; } return cnt; }
template <typename DataType> DataType LinkList<DataType>::Get(int i) { if (i < 1 || i > this->Length()) { throw "位置不存在"; } Node<DataType>* temp = this->header; for (int j = 0; j < i; j++) { temp = temp->next; } return temp->data; }
template <typename DataType> int LinkList<DataType>::Locate(DataType x) { Node<DataType>* temp = header; for (int i = 0; i < this->Length(); i++) { temp = temp->next; if (temp->data == x) { return i + 1; } } return 0; }
template <typename DataType> void LinkList<DataType>::Insert(int i, DataType x) { if (i < 1 || i > this->Length() + 1) throw "位置错误";
Node<DataType>* temp = header, *new_node = new Node<DataType>; for (int j = 0; j < i - 1; j++) { temp = temp->next; } new_node->data = x; new_node->next = temp->next; temp->next = new_node; }
template <typename DataType> DataType LinkList<DataType>::Delete(int i) { if (i < 1 || i > this->Length()) throw "位置错误";
DataType del = this->Get(i);
Node<DataType>* node = header, *temp = nullptr; for (int j = 0; j < i - 1; j++) { node = node->next; } temp = node->next; node->next = node->next->next; delete(temp);
return del; }
template <typename DataType> int LinkList<DataType>::Empty() { if (this->header->next == nullptr) { return 1; } return 0; }
template <typename DataType> void LinkList<DataType>::PrintList() { if (this->Empty()) { cout << "{}" << endl; return; }
Node<DataType>* temp = header->next;
cout << "{" << temp->data; while (temp->next != nullptr) { temp = temp->next; cout << "," << temp->data; } cout << "}" << endl; }
|
Main.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| #include <iostream> #include "LinkList.h"
using namespace std;
template <typename DataType = int> void Menu(int choose, LinkList<>* list);
void Clear();
int main() { int init[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; LinkList<> list(init, 8); int choose = -1;
while (choose) { cout << "--------------------------------" << endl; cout << "元素[" << list.Length() << "]个|单链表状态"; list.PrintList(); cout << "1、插入一个数字" << endl; cout << "2、指定位置插入一个数字" << endl; cout << "3、获取某个数的具体位置" << endl; cout << "4、获取一个具体位置的数" << endl; cout << "5、删除一个指定位置的数" << endl; cout << "0、退出演示" << endl; cout << "请输入对应服务编号:"; cin >> choose; try { Menu(choose, &list); } catch (const char* e) { cout << "出错啦,错误消息:" << e << endl; } cout << endl << "--------------------------------" << endl; } }
template <typename DataType = int> void Menu(int choose, LinkList<>* list) { int in_1 = 0, in_2 = 0, temp_1 = 0; switch (choose) { case 1: cout << "请输入要插入的数字:"; cin >> in_1; list->Insert(list->Length() + 1, in_1); break; case 2: cout << "请输入指定位置与要插入的数字:"; cin >> in_1 >> in_2; list->Insert(in_1, in_2); break; case 3: cout << "请输入要查询的数:"; cin >> in_1; temp_1 = list->Locate(in_1); if (temp_1) { cout << "所查数第一次出现的位置是:" << temp_1 << endl; } else { cout << "没有查到哦~" << endl; } break; case 4: cout << "请输入要查找的位置:"; cin >> in_1; temp_1 = list->Get(in_1); cout << "所在位置的数是:" << temp_1 << endl; break; case 5: cout << "请输入要删除的位置:"; cin >> in_1; list->Delete(in_1); break; case 0: cout << "感谢体验,再见~" << endl; break; default: cout << "输入有误" << endl; } }
void Clear() { cout << "\x1B[2J\x1B[H"; }
|
运行效果和顺序表差不多,就不过多展示了
顺序栈
栈结构就是先入后出,后入先出,使用顺序栈实现四则运算
MyMath.h
1 2 3 4 5 6 7
| #pragma once
int Precedence(char op);
float Operate(float left, float right, char op);
|
SeqStack.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #pragma once #include <iostream>
using namespace std;
const int StackSize = 10;
template <typename DataType = int> class SeqStack { public: SeqStack(); ~SeqStack(); void Push(DataType x); DataType Pop(); DataType GetTop(); int Empty(); private: DataType data[StackSize]; int top; };
template <typename DataType> SeqStack<DataType>::SeqStack() { this->top = -1; }
template <typename DataType> SeqStack<DataType>::~SeqStack() {
}
template <typename DataType> void SeqStack<DataType>::Push(DataType x) { if (this->top == StackSize - 1) throw "栈溢出"; this->data[++top] = x; }
template <typename DataType> DataType SeqStack<DataType>::Pop() { return this->data[this->top--]; }
template <typename DataType> DataType SeqStack<DataType>::GetTop() { return this->data[this->top]; }
template <typename DataType> int SeqStack<DataType>::Empty() { return (this->top == -1) ? 1 : 0; }
|
MyMath.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include "MyMath.h"
int Precedence(char op) { switch (op) { case '(': return 0; case '#': return 1; case '=': return 1; case '+': return 2; case '-': return 2; case '*': return 3; case '/': return 3; case ')': return 4; default: throw "不支持的运算符"; } }
float Operate(float left, float right, char op) { switch (op) { case '+': return left + right; case '-': return left - right; case '*': return left * right; case '/': return left / right; default: throw "不支持的运算符"; } }
|
Main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include "SeqStack.h" #include "MyMath.h" #include <string>
using namespace std;
int main() { string allOps = "#+-*/=()", userIn = ""; SeqStack<float> nums; SeqStack<char> ops; char op = '\0'; float num = 0, left = 0, right = 0; ops.Push('#'); cout << "请输入你的表达式\n每次输入[运算数]or[运算符]" << endl; do { if (userIn != "=") { cout << "你的输入:"; cin >> userIn; }
if (userIn == "(") { ops.Push('('); continue; }
if (allOps.find(userIn) == string::npos) { num = stof(userIn); nums.Push(num); continue; }
if (userIn == ")") { while ((op = ops.Pop()) != '(') { right = nums.Pop(); left = nums.Pop(); nums.Push(Operate(left, right, op)); } continue; }
if (Precedence(ops.GetTop()) >= Precedence(userIn[0])) { right = nums.Pop(); left = nums.Pop(); nums.Push(Operate(left, right, ops.Pop())); if (userIn != "=") { ops.Push(userIn[0]); } continue; }
if (userIn != "=") { ops.Push(userIn[0]); } } while (userIn != "=" || ops.GetTop() != '#');
cout << "计算结果:" << nums.GetTop();
return 0; }
|
运行效果
队列
先入先出,后入后出,这里使用循环队列完成了一个门诊看病的案例
CirQueue.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #pragma once
const int QueueSize = 50;
template <typename DataType> class CirQueue { public: CirQueue(); ~CirQueue(); void EnQueue(DataType x); DataType DeQueue(); DataType GetHead(); int Empty(); int Size(); private: DataType data[QueueSize]; int start, end, length; };
template <typename DataType> int CirQueue<DataType>::Size() { return length; }
template <typename DataType> CirQueue<DataType>::CirQueue() { this->start = QueueSize - 1; this->end = QueueSize - 1; this->length = 0; }
template <typename DataType> CirQueue<DataType>::~CirQueue() {
}
template <typename DataType> void CirQueue<DataType>::EnQueue(DataType x) { if ((this->end + 1) % QueueSize == this->start) throw "满"; this->data[this->end = ((this->end + 1) % QueueSize)] = x; this->length++; }
template <typename DataType> DataType CirQueue<DataType>::DeQueue() { this->length--; if (this->start == this->end) throw "空队"; return this->data[this->start = (this->start + 1) % QueueSize]; }
template <typename DataType> DataType CirQueue<DataType>::GetHead() { if (this->start == this->end) throw "空队"; return this->data[(this->start + 1) % QueueSize]; }
template <typename DataType> int CirQueue<DataType>::Empty() { return length ? 0 : 1; }
|
Main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| #include "CirQueue.h" #include <iostream> #include <string>
using namespace std;
struct Sick { string id; string name; };
Sick* choiceHandle(int choice, CirQueue<Sick*>* sicks, Sick* current);
int main() { int userIn = 0; CirQueue<Sick*>* sicks = new CirQueue<Sick*>; struct Sick* sick = nullptr; do { try { cout << "----------输入数字选择对应功能----------" << endl; if (sick == nullptr) { cout << "----------------诊室空闲----------------" << endl; } else { cout << "---编号[" + sick->id + "]|姓名[" + sick->name + "]正在门诊-----" << endl; } if (sicks->Size()) { cout << "---请编号[" + sicks->GetHead()->id + "]|姓名[" + sicks->GetHead()->name + "]做好准备-----" << endl; } cout << "---------当前还有[" << sicks->Size() << "]人正在排队----------" << endl; cout << "--------------1、录入病人---------------" << endl; cout << "--------------2、呼叫病人---------------" << endl; cout << "--------------0、退出系统---------------" << endl; cout << "请选择:"; cin >> userIn; sick = choiceHandle(userIn, sicks, sick); cout << "----------------------------------------" << endl; } catch (const char* ex) { cout << "错误的操作" << endl; exit(-1); } } while (userIn);
return 0; }
Sick* choiceHandle(int choice, CirQueue<Sick*>* sicks, Sick* current) { struct Sick* sick; switch (choice) { case 0: cout << "再见" << endl; return nullptr; case 1: cout << "请输入编号及姓名" << endl; sick = new Sick; cin >> sick->id >> sick->name; sicks->EnQueue(sick); return current; case 2: if (sicks->Size()) { sick = sicks->DeQueue(); } else { cout << "无人等待" << endl; sick = nullptr; } return sick; default: cout << "不支持的选项" << endl; return current; } }
|
运行截图
模式匹配
字符串特有的功能
BF
暴力算法
Main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <iostream> #include <stdlib.h>
using namespace std;
int BF(char* s, char* t) { int start = 0; int i = 0, j = 0;
while ((s[i] != '\0') && (t[j] != '\0')) {
if (s[i] == t[j]) { i++; j++; }
else { start++; i = start; j = 0; } }
if (t[j] == '\0') { return start + 1; } else { return 0; }
}
int main() { char *s = (char*) malloc(1024), * t = (char*)malloc(1024);
cout << "请输入主串:"; cin >> s; cout << "请输入子串:"; cin >> t;
if (int index = BF(s,t)) { cout << "子串第一次在主串中出现的下标是:" << index; } else { cout << "没有匹配到子串"; }
free(s); free(t);
return 0; }
|
运行截图
KMP
对我来说很烧脑,我这里的实现有问题,但是能力只能先这样了
Main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| #include <stdlib.h> #include <iostream>
using namespace std;
struct Arr { int* data; int length; };
Arr* getNext(char* t);
int KMP(char* s, char* t);
int main() { char* s = (char*) malloc(1024); char* t = (char*)malloc(1024);
cout << "请输入主串:"; cin >> s; cout << "请输入子串:"; cin >> t;
int index = KMP(s, t); if (index == -1) { cout << "没有在主串中找到子串"; } else { cout << "子串在主串中第一次出现的下标为:" << index; } free(s); free(t);
return 0; }
Arr* getNext(char* t) { Arr* next = new Arr{ nullptr,0 };
while (t[next->length] != '\0') { next->length++; }
next->data = (int*)malloc(sizeof(int) * (next->length));
next->data[0] = 0; next->data[1] = 0;
for (int i = 2; i < next->length; i++) { int max = i - 1; next->data[i] = 0; for (int j = max; j >= 1; j--) { int flag = true; for (int k = 0; k < j; k++) { if (t[k] != t[max - j + k + 1]) { flag = false; break; } } if (flag) { next->data[i] = j; break; } } }
return next; }
int KMP(char* s, char* t) { Arr* next = getNext(t); int start = 0, t_i = 0;
while (s[start] != '\0' && t[t_i] != '\0') { if (s[start] == t[t_i]) { t_i++; } else { t_i = next->data[t_i + 1]; } start++; }
if (t[t_i] == '\0') { return start - next->length; }
return -1; }
|
运行截图
扩展
- 双向链表:一个结点包含前驱与后继的结点指针
- 循环链表:
- 单链表:尾结点的后继结点指针指向头结点
- 双向链表:头结点的前驱结点指针指向尾结点,尾结点的后继结点指针指向头结点