虽然兴趣使然写了很多代码or算法题,但是对于数据结构其实并没有系统地去了解一遍,
现今发现自己想升本的学校要考数据结构,故打算根据一本教材来完整地学习,
这些关于<数据结构>的随笔会有很多
我的学习大纲:
1.绪论
(1)数据、数据元素、数据项、数据对象、数据结构、逻辑结构、物理结构、元素、结点等基本概念。抽象数据类型的定义、表示和实现方法。
(2)算法、算法的特性、如何用类C语言来描述算法。
(3)算法设计的基本要求以及计算语句频度和估算算法时间复杂度的方法。
2.线性表
(1)线性表的定义和操作。
(2)顺序存储线性表的实现和运算。
(3)链式存储线性表,带有附加表头结点和不带附加表头结点的单链表、循环链表和双向链表的实现和查找对插入、删除等基本操作。
3.栈和队列
(1)栈和队列的定义及其存储结构、循环队列。
(2)栈和队列的主要运算。
(3)栈的应用举例,如:数制转换、表达式求值等。
4.串
(1)串的定义、空串、空格串。
(2)串的基本操作。
(3)串的顺序存储结构及在顺序存储结构下基本操作的实现。
(4)串的模式匹配算法。
5.树和二叉树
(1)树的定义和术语。
(2)二叉树(完全二叉树、满二叉树)的定义和性质、二叉树的存储结构(顺序表示法和二叉链表表示法)。
(3)二叉树遍历的递归算法。
(4)树和森林转换为二叉树的方法。
6.图
(1)图的定义。
(2)图的基本术语。
①图及无向图、有向图、网、子图、连通图、强连通图。
②顶点的度、入度、出度。
③顶点间路径、路径长度、环。
(3)图的存储结构
①邻接矩阵
②邻接表(含逆邻接表)
(4)遍历图
①深度优先搜索遍历图的算法及其时间复杂度。
②广度优先搜索遍历图的思想及其时间复杂度。
(5)生成树
①生成树、最小生成树的概念。
②最小生成树的构造过程(Prim算法和Kruskal算法)及其时间复杂度。
(6)两类求最短路径问题的解法。
8.排序
(1)排序的目的、分类和排序方法的稳定性的定义。
(2)插入排序
①直接插入排序的算法。
②希尔排序的思想。
(3)选择排序
①简单的选择排序的算法。
③堆的定义、堆排序的思想。
(4)归并排序的思想。
(5)基数排序的思想及特点。
(6)各种内部排序方法的比较。
9.查找
(1)查找、关键字、平均查找长度等概念。
(2)静态查找表的查找算法及其效率(最坏和平均查找长度)。
①顺序查找
②分块查找
(3)动态查找表
①二叉排序树定义、构造过程及其查找算法和效率。
(4)哈希表
①哈希表的特点。
②构造哈希函数的方法(除留余数法等)。
③处理冲突的方法。
在写这篇随笔之前,我只是以两倍速过了一遍网易云课堂 [何钦铭] [陈越] 两位老师的 数据结构 视频课程,
https://mooc.study.163.com/course/1000033001?tid=2402970002&_trace_c_p_k2_=68e70883ef344689ac02775
所以随笔的内容是,【尝试实现里边数据结构的具体代码】,我会以C++和指针(因为算法书没有使用面向对象)来实现,比较难理解的,用WPF
C#和面向对象来写可视化分析。
前言:
数据结构学到最后,可以合并到只剩下几个概念在脑海中,换句话说,就是理解了一个算法中最核心解决问题的点,
如希尔排序为什么比插入排序快。因为希尔排序有可能一次使两个逆序对归位。这是造成效率差异的核心,这就是一个概念,
真正学会数据结构,就是会灵活运用已知概念来优化算法或者优化结构。
线性表:
1.数组:
太基础了,int arr[10];......
2.链表
链表是数组为了克服空间紧密带来的缺点而产生的,它的优点之一就是动态长度
实现:( 我用的IDE是VS2019, C++控制台程序,新建一个粘贴就可以跑了)
#include <iostream> using namespace std; struct Node { int content;//节点存放的内容 Node* Next;//节点的下一个节点 };//节点的结构 struct List { Node* head;//链表头 Node* head2;//链表物理上的头 void Init() { head2 = (Node*)malloc(sizeof(Node));//申请空间 head2->Next = head;//初始化head(链表头) head = (Node*)malloc(sizeof(Node));//申请空间 head = NULL;//由于没有元素,head为NULL } bool IsNull() { if (head == NULL)return true; return false; } int GetLength() { Node* p = head; int len = 0; while (p != NULL) { p = p->Next; len++; } return len; } int Locate(int _content) { Node* p = head; int len = 0; while (p != NULL) { if (_content == p->content) return len; p = p->Next; len++; } return -1; } Node* Find(int _content) { Node* p = head; while (p != NULL) { if (_content == p->content) return p; p = p->Next; } return NULL; } bool Insert(int index, int _content) { //在插入之前要new一个节点, Node* newNode = (Node*)malloc(sizeof(Node)); //newNode->Next = NULL; newNode->content = _content; Node* p = head; int len = 0; if (head == NULL)//空表走另一个流程 { head = newNode; head->Next = NULL; return true;//返回 } else if (index == 0)//不是空表,但是往头节点插入也会产生问题, { newNode->Next = p; head = newNode; return true;//返回 } else//不是空表,不是头节点,的一般情况 { while (p != NULL) { if (index - 1 == len)//插入这里 { if (p->Next != NULL)//如果不是队尾,就要把后面的链连到当前节点 { newNode->Next = p->Next; } else { newNode->Next = NULL; } p->Next = newNode; return true; } p = p->Next; len++; } } return false; } int Delete(int index) { Node* p = head; int len = 0; if (index == 0) { //要删除头节点 if (head == NULL)return false;//如果是空表, head = head->Next; int retnum = p->content; delete(p); return retnum; } else//删除的不是头节点 { while (p != NULL) { if (index - 1 == len)//遍历到要删除的前面一个 { if (p->Next != NULL) { Node* d = p->Next;//保存要删除的节点的引用到d if (d->Next != NULL)//把后面的接到前面 { p->Next = d->Next; delete(d); return true; } } } p = p->Next; len++; } } return false; } void Show() { Node* p = head; int len = 0; while (p != NULL) { cout << len << "号元素 :" << p->content << endl; p = p->Next; len++; } } };//表的结构 int mai2n() { List a; a.Init(); cout << "是否为空" << a.IsNull() << endl; a.Insert(1, 1101); cout << "是否为空" << a.IsNull() << endl; a.Insert(1, 1102); a.Insert(1, 1103); a.Insert(1, 1104); a.Insert(1, 1105); a.Insert(1, 1106); a.Show(); cout << "显示完毕" << endl; cout << "删除index为1的链表" << endl; a.Delete(1); a.Delete(0); a.Delete(0); a.Delete(0); a.Delete(0); a.Delete(0); a.Delete(0); cout << "是否为空" << a.IsNull() << endl; a.Show(); cout << "删除10" << endl; a.Delete(10); a.Show(); cout << "宽度为" << a.GetLength() << endl; }
包含了线性表的,初始化,求长度,插入,删除,查找,定位,6个主要操作集,
3.栈
我感觉栈其实和队列一样,是对线性表的一种约束型算法,
栈的约束是,先进后出。
数组实现栈:
比较简单
// datastruct.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 #include <iostream> using namespace std; struct Stack {//这个翻译过来好像是栈 int arr[5];//栈有一个数组 int len = 5;//顺便记录下长度 int top = -1; //栈顶0才是第一个所以是-1 void Init()//初始化 { } bool IsNull() { if(top==-1) return true; return false; } bool IsFull() { if (top == len-1) return true; return false; } bool Push(int number) { if (top != len-1) { arr[++top] = number; return true; } return false; } int Pop() { if (top != -1) { return arr[top--]; } return 0x7fffffff;//原来C++允许不返回值,这时返回一个异常大的值来获取信息 } }; int main() { Stack s; cout << "NULL=" << s.IsNull() << endl; s.Push(6); cout << "NULL=" << s.IsNull() << endl; s.Push(5); s.Push(1); s.Push(4); s.Push(3); s.Push(2); cout <<"FULL="<< s.IsFull() << endl; int n; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n) << endl; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n) << endl; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n) << endl; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n) << endl; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n) << endl; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n ) << endl; n = s.Pop(); cout << (n == 0x7fffffff ? -999 : n) << endl; n = s.Pop(); return 0; }
链表实现:
(将链表的结构添加如下代码)
void Push(int num) { Insert(0, num); } int Pop()//正常使用应该返回一个结构体(判断是否为null),而不是一个单独类型 { return Delete(0); }
很明显,栈的push pop 就是简单包装一下insert delete
队列:
数组实现队列:
#include <iostream> using namespace std; struct Queue { int arr[5]; int maxlen; int left;//队列尾巴 int right;//队列头 int len; void Init() { maxlen = 5; left = 0; right = -1; len = 0; } bool IsNull() { if (len==0)return true; return false; } bool IsFull() { if (len == maxlen)return true; return false; } bool Enqueque(int num) { bool rt=false; if (!IsFull())//一定不能满 { right++; arr[right%maxlen] = num; len++; rt = true; } return rt; } int Dequeque() { int rt = 0x7fffffff; if (!IsNull())//一定不能是空的 { rt = arr[left % maxlen]; len--; left++; } return rt; } void Show() { for (int i=0; i < len ; i++) { cout<< arr[(left+i)%maxlen]<< " "; } cout << endl; } }; int main() { Queue q; q.Init(); q.Enqueque(1); q.Show(); q.Enqueque(2); q.Show(); q.Enqueque(3); q.Show(); q.Enqueque(4); q.Show(); q.Enqueque(5); q.Show(); cout << "入队6" << endl; q.Enqueque(6); q.Show(); cout << "出队" << q.Dequeque() << endl; q.Show(); cout << "出队" << q.Dequeque() << endl; q.Show(); cout << "出队" << q.Dequeque() << endl; q.Show(); cout << "出队" << q.Dequeque() << endl; q.Show(); q.Enqueque(7); cout << "入队7" << endl; q.Show(); cout << "出队" << q.Dequeque() << endl; q.Show(); return 0; }
链表实现队列:
...跟栈一样,限制一下而已
bool EnQueue(int num) { return Insert(0, num);//插入队首 } int DeQueue( ) { cout << "GetLength()-1 = "<< GetLength() - 1 << endl; return DeleteEnd(); } int DeleteEnd()//从从Delete修改而来 { Node* p = head; Node* old = head; if (p == NULL)return 0x7fffffff; while (p->Next != NULL) { old = p; p = p->Next; } old->Next = NULL; int ret= p->content; delete(p); return ret; }
线性表到此结束,其实还有很多操作集,但是这个大纲有很多内容暂时不用考虑到.就偷个懒把。。