我学《数据结构与算法》 20155314刘子健
我学《数据结构与算法》
我眼中的数据结构
一句话
组织数据的方式
分类
- 逻辑结构
- 线性结构(一对一)
- 非线性结构
- 集合(无逻辑关系)
- 树(一对多)
- 图(网)(多对多)
- 存储结构(物理结构)
- 顺序
- 链式
- 散列
- 索引
整合起来看就是
基本操作
- 增
- 删
- 查
- 改
我学过的算法
- 排序
- 基于关键字比较
- 插入排序
- 快速排序
- 堆排序
- 归并排序
- 不基于关键字比较
- 计数排序
- 基数排序
- 基于关键字比较
- 查找
- 静态
- 折半查找
- 动态
- 散列查找
- 基于二叉搜索树的查找
- 静态
- 遍历
- 二叉树的遍历
- 先序遍历
- 中序遍历
- 后序遍历
- 图的遍历
- 深度优先
- 广度优先
- 拓扑排序
- 二叉树的遍历
- 优化
- 按问题组织算法
- 最优二叉树——Huffman算法
- 最小生成树
- Prim算法
- Kruskal算法
- 最短路径
- Dijkstra算法
- Floyd算法
- 关键路径
- 按策略组织算法
- 贪心算法
- 动态规划
- 按问题组织算法
- 字符串匹配——KMP算法
- 经典问题
- 背包问题
- 0-1背包问题——动态规划
- 分数背包问题——贪心策略
- N皇后问题——回溯法
- 旅行商问题——动态规划
- 子集和问题
- 回溯法
- 动态规划——转化为0-1背包问题
- 背包问题
整合起来看就是
C语言实现
数据结构(存储结构)
- 线性表
-
顺序表
#define LIST_INIT_SIZE 80 //线性表存储空间的初始分配量 #define LISTINCREMENT 10 //线性表存储空间的分配增量 typedef int ElemType; typedef struct { ElemType *elem; //存储空间基址 int length; //当前长度 int listsize; //当前分配的存储容量(以sizeof(ElemType)为单位) }SqList; //顺序表
-
单链表
typedef int ElemType; typedef struct LNode { ElemType data; //数据域 struct LNode *next; //指针域 }LNode,*LinkList; LinkList L; //L为单链表的头指针
-
- 栈(先进后出)
-
顺序栈
#define STACK_INIT_SIZE 100 //最大栈长度 typedef int ElemType; typedef struct { ElemType *base; //栈底指针 ElemType *top; //栈顶指针 int stacksize; }SqStack;
-
链栈
#define STACK_INIT_SIZE 100 typedef int ElemType; typedef struct Node { ElemType data; struct Node *next; }*LinkStack;
-
- 队列(先进先出)
-
循环队列
#define MAXQSIZE 100 //最大队列长度 typedef int ElemType; typedef struct { ElemType *base; //动态分配存储空间 int front; //头指针,若队列不空,指向队列头元素 int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置 int queuesize; }SqQueue;
-
链队列
typedef int QElemType; typedef struct QNode { //结点类型 QElemType data; struct QNode *next; }QNode,*QueuePtr; typedef struct { //链队列类型 QueuePtr front; //队头指针 QueuePtr rear; //队尾指针 }LinkQueue;
-
- 树
-
二叉链表
typedef int ElemType; typedef struct BiTNode { //结点结构 ElemType data; struct BiTNode *lchild,*rchild; //左右孩子指针 }BiTNode,*BiTree; BiTree T; //二叉链表的根指针
-
B树
#define m 3 // B树的阶,此设为4 typedef int KeyType; typedef struct { KeyType key; char data; }Record; typedef struct BTNode { int keynum; //结点中关键字个数,结点大小 struct BTNode *parent; //指向双亲结点的指针 KeyType key[m+1]; //关键字向量(0号单元不用) struct BTNode *ptr[m+1]; //子树指针向量 Record *recptr[m+1]; //记录指针向量(0号单元不用) }BTNode,*BTree; //B树结点和B树的类型 typedef struct { BTNode *pt; //指向找到的结点的指针 int i; //1..m,在结点中的关键字序号 int tag; //标志查找成功(=1)或失败(=0) } Result; //在B树的查找结果类型
-
- 图
-
邻接矩阵
#define MAX_VERTEX_NUM 100 typedef char VertexType; typedef int EdgeType; typedef enum { DG,UDG }GraphKind; typedef struct { //图的定义 VertexType vexs[MAX_VERTEX_NUM]; //存储顶点信息 EdgeType arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵,存储边的信息 int vexnum,arcnum; //顶点数,边数 GraphKind kind; //图的种类标志 }MGraph;
-
邻接表
#define MAX_VERTEX_NUM 100 typedef char VertexType; typedef enum { DG,UDG }GraphKind; typedef struct ArcNode { //边的结点结构 int adjvex; //该边所指向的顶点的位置 struct ArcNode *nextarc; //指向下一条边的指针 }ArcNode; typedef struct VNode { //顶点的顶点结构 VertexType data; //顶点信息 ArcNode *firstarc; //指向第一条依附于该顶点的边 }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct { //图的定义 AdjList vertices; int vexnum,arcnum; //顶点数,边数 GraphKind kind; //图的种类标志 }ALGraph;
-
算法
-
排序算法
#include <stdio.h> #include <stdlib.h> #define N 5 void BubbleSort(int a[]); void SelectionSort(int a[]); void InsertionSort(int a[]); void QSort(int a[],int s,int t); int Partition(int R[],int low,int high); void CountingSort(int a[],int k); int max(int a[]); void HeapSort(int a[]); void MaxHeapify(int a[],int s,int m); void BuildMaxHeap(int a[]); void MergeSort(int a[],int s,int t); void Merge(int a[],int i,int m,int n); void main() { int i,j,temp; int a[N],b[N]; printf("请输入%d个整数:",N); for(i=0;i<N;i++) { scanf("%d",&a[i]); } BubbleSort(a); //冒泡排序 /*for(i=0;i<N;i++) //冒泡排序 { for(j=0;j<N;j++) { if(a[j]>a[j+1]) { temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } }*///冒泡排序 SelectionSort(a); //InsertionSort(a); //插入排序 /*for(i=0,j=1;i<N,j<N+1;i++,j++) //将下标改为从1开始 { b[j]=a[i]; } QSort(b,1,N); for(i=1;i<N+1;i++) { printf("%d ",b[i]); }*/ //快速排序 //CountingSort(a,max(a)); //计数排序 //HeapSort(a); //堆排序 /*for(i=0,j=1;i<N,j<N+1;i++,j++) //将下标改为从1开始 { b[j]=a[i]; } MergeSort(b,1,N); for(i=1,j=0;i<N+1,j<N;i++,j++) //将数组下标还原为从0开始 { a[j]=b[i]; }*/ //归并排序 for(i=0;i<N;i++) { printf("%d ",a[i]); } } void BubbleSort(int a[]) //冒泡排序 { int i,j,temp; for(i=0;i<N-1;i++) { for(j=i+1;j<N;j++) { if(a[i]>a[j]) { temp=a[i]; a[i]=a[j]; a[j]=temp; } } } } void SelectionSort(int a[]) //选择排序 { int i,j,k,temp; for(i=0;i<N-1;i++) { k=i; //从下标为0处开始记录 for(j=i+1;j<N;j++) { if(a[j]<a[k]) { k=j; //记录最小数下标位置 } } if(k!=i) //优化处理:若最小数所在的下标位置不在下标位置i,则交换 { temp=a[k]; a[k]=a[i]; a[i]=temp; } } } void InsertionSort(int a[]) //插入排序 { int i,j,b[N]; for(i=0,j=1;i<N,j<N+1;i++,j++) //将下标改为从1开始,便于设置监视哨a[0] { b[j]=a[i]; } for(i=2;i<=N;i++) { if(b[i]<b[i-1]) { b[0]=b[i]; //复制为监视哨 for(j=i-1;b[0]<b[j];j--) { b[j+1]=b[j]; } b[j+1]=b[0]; } } for(i=1,j=0;i<N+1,j<N;i++,j++) //将数组下标还原为从0开始 { a[j]=b[i]; } } void QSort(int a[],int s,int t) //快速排序 { int pivotloc; if(s<t-1) //长度大于1 { pivotloc=Partition(a,s,t); //对a[]进行一次划分 QSort(a,s,pivotloc-1); //对左子序列递归排序,pivotloc是轴位置 QSort(a,pivotloc+1,t); //对右子序列递归排序 } } int Partition(int R[],int low,int high) { int pivotkey; R[0]=R[low]; pivotkey=R[low]; //"轴" while (low<high) { while (low<high&&R[high]>=pivotkey) high--; R[low]=R[high]; while (low<high&&R[low]<=pivotkey) ++low; R[high]=R[low]; } R[low]=R[0]; return low; } void CountingSort(int a[],int k) //计数排序 { int i,j; int C[N]; //引入索引数组C int R[N]; //新建存储数组R for(i=0;i<=k;i++) { C[i]=0; //初始化数组c } for(i=0;i<N;i++) { C[a[i]]++; //c[i]中存值等于i的元素个数 } for(i=1;i<=k;i++) { C[i]=C[i]+C[i-1]; //c[i]中存值小于等于i的元素个数 } for(j=N-1;j>=0;j--) { R[C[a[j]]]=a[j]; C[a[j]]--; //下一个值为a[j]的元素被放到a[j]的前一个位置 } for(i=0;i<N;i++) { a[i]=R[i+1]; } } int max(int a[]) { int i; int max; max = a[0]; for(i=1;i<N;i++) { if (max<a[i]) max=a[i]; } return max; } void HeapSort(int a[]) //堆排序 { int temp,i; BuildMaxHeap(a); //建大顶堆 for(i=N;i>1;i--) { temp=a[0]; //将堆顶元素和当前未经排序子序列a[0...i-1]中最后一个元素交换 a[0]=a[i-1]; a[i-1]=temp; MaxHeapify(a,0,i-2); //调整a[0...i-2]使其成为大顶堆 } } void MaxHeapify(int a[],int s,int m) //维护堆的性质 { int rc,j; rc=a[s]; //暂存a[s] for(j=2*s;j<=m;j*=2) { if(j<m&&a[j]<a[j+1]) j++; //左右"孩子"之间先进行相互比较,令j指示较大的关键字所在位置 if(rc>=a[j]) break; //再作"根"和"孩子"之间比较,若">="成立,则说明已找到rc的插入位置s,不需继续向下调整 a[s]=a[j]; s=j; //否则关键字上移,仍需继续向下调整 } a[s]=rc; //将调整前的堆顶插入到s位置 } void BuildMaxHeap(int a[]) //建堆 { int i; for(i=N/2-1;i>=0;i--) { MaxHeapify(a,i,N); //建大顶堆 } } void MergeSort(int a[],int s,int t) //归并排序 { int m; if(s<t) { m=(s+t)/2; //分解 MergeSort(a,s,m); //解决 MergeSort(a,m+1,t); Merge(a,s,m,t); //合并 } } void Merge(int a[],int i,int m,int n) //归并有序序列a[i...m]和a[m+1...n] { int j,k,p,q; int R[N]; for(j=i;j<=n;j++) { R[j]=a[j]; //复制 } for(j=m+1,k=i;i<=m&&j<=n;k++) { if(R[i]<=R[j]) a[k]=R[i++]; else a[k]=R[j++]; } if(i<=m) { for(p=i,q=k;p<=m,q<=n;p++,q++) { a[q]=R[p]; } } if(j<=n) { for(p=j,q=k;p<=n,q<=n;p++,q++) { a[q]=R[p]; } } }