大话数据结构
目录:
数据结构和算法理论
线性表
栈与队列
串
树
查找
排序
数据结构和算法理论
数据
描述客观事实的符号,是计算机可操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。
数据元素
是组成数据的,有一定意义的基本单位,在计算机中通常作为整体处理,也称为记录。比如 人。
数据项
一个数据元素可以由若干数据项组成。比如 手,脚
数据对象
是性质相同的数据元素的集合,是数据的子集。
数据结构
是相互存在一种或多种特定关系的数据元素的集合。
数据的关系存在 逻辑关系和物理结构
逻辑关系
集合关系
线性关系
树形结构
图形结构
物理结构
顺序存储结构
链式存储结构
算法
算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列。并且每个指令代表一个或多个操作。
算法的特性
输入输出
有穷性
确定性
可行性
算法的设计要求
正确性
可读性
健壮性
算法效率的度量方法
事后统计法
事前估算法
函数的渐进增长
算法时间复杂度
大0推导法
用常数1取代运行时间中的所有加法常数
只保留最高阶项
去掉前面的常数
常数阶,线性阶,对数阶,平方阶,立方阶,指数阶,阶乘阶
线性表
零个或多个数据元素的有限序列
栈与队列
栈:是限定仅在表尾进行插入和删除操作的线性表。后进先出LFIO,能操作的一段叫做栈顶,另一端称为栈底。
队列:是只允许在一端进行插入,另一端进行删除的线性表。FIFO先进先出,允许插入的称为队尾,允许删除的为对头。
串
由零个或多个字符组成的有限序列,又叫做字符串
树
由多个节点组成。
节点
度
深度
双亲
祖先
孩子
兄弟
树的存储结构
双亲表示法
孩子表示法
孩子兄弟表示法
二叉树
每个节点最多有2个子树
左子树和右子树是有顺序的,不能颠倒
即使树中只有一个棵子树也要区分左或右
二叉树的存储结构
完全二叉树 才使用顺序存储就是数组
二叉链表 节点 有左右孩子
遍历二叉树
指从根节点出发按某种次序依次访问二叉树中所有的节点,使得每个节点被访问一次且仅被访问一次
前序遍历 根左右
中序遍历 左根右
后序遍历 左右根
层序遍历 一层一层访问
二叉树的建立
查找
顺序查找
二分查找
二叉排序树
平衡二叉树
散列查找-哈希表
散列函数的构造方法
计算简单
散列地址分布均匀
直接定址法:取关键字的某个线性函数值为散列地址。
数字分析法:
平方求中法:
折叠法:
除留余数法:
随机数法
处理冲突方法
开放定址法:也叫线性探测法
再散列函数法
链地址法:
公共溢出区法
排序
基础代码
/** 交换数组中的 2个 下标位置值 ,i被交换,j交换 */
private static void swap(int[] des, int i, int j) {
int temp = des[i];
des[i] = des[j];
des[j] = temp;
}
/** 打印数组 */
public static void printArray(String tag, int[] data) {
StringBuilder builder = new StringBuilder(tag);
for (int i = 0; i < data.length; i++) {
builder.append(data[i] + ",");
}
System.out.println(builder);
}
/** 打印单个 */
public static void printInt(String tag, int data) {
System.out.println(tag + "=" + data);
}
/** 打印单个 */
public static void printInt(String msg) {
System.out.println(msg);
}
int[] bubble = { 4, 5, 3, 1, 2 };
int[] inset = { 0, 5, 3, 4, 6, 2 };// 0作为临时变量或者哨兵
int[] shell = { 0, 7, 5, 8, 3, 2, 4, 6, 1 };// 0作为临时变量或者哨兵
int[] merge = { 7, 5, 8, 3, 2, 4, 6, 1};
int[] quick = { 7, 5, 8, 3, 2, 4, 6, 1 };
冒泡排序
/** 冒泡 //两两比较相邻记录的关键字,如果反序则交换 */
private static void bubble(int[] data) {
printArray("----------------bubble----------", data);
int len = data.length;
boolean flag = true;
for (int i = 0; i < len && flag; i++) {
flag = false;
for (int j = len - 1; j > i; j--) {
if (data[j] < data[j - 1]) {
swap(data, j, j - 1);
flag = true;
printArray("swap:", data);
}
}
printInt("--------------------" + i);
}
printArray("----------------bubble----------", data);
}
选择排序
/** 选择,改进型 交换,一次循环记录最小的,然后换一次 */
private static void select(int[] data) {
printArray("----------------select----------", data);
int len = data.length;
int min = 0;
for (int i = 0; i < len; i++) {
printInt("-------------------------" + i);
min = i;
for (int j = i + 1; j < len; j++) {
if (data[j] < data[min]) {
min = j;
}
}
if (i != min) {
swap(data, i, min);
printArray("swap:", data);
}
}
printArray("----------------select----------", data);
}
插入排序
/** 简单插入,慢慢移动位置 插入到指定位置,和排队类似 */
private static void insert(int[] newSrc) {
printArray("----------------insert----------", newSrc);
int i, j;
for (i = 2; i < 6; i++) {
printInt("-------------------------" + i);
if (newSrc[i] < newSrc[i - 1]) {
newSrc[0] = newSrc[i];// 寄存 i的值
printArray("insert-zero-", newSrc);
for (j = i - 1; newSrc[j] > newSrc[0]; j--) {
newSrc[j + 1] = newSrc[j];// 往后移动一个位置 空出合适的位置
printArray("insert-two-", newSrc);
}
newSrc[j + 1] = newSrc[0]; // 把值插入 空出的位置
printArray("insert-one-", newSrc);
}
}
printArray("----------------insert----------", newSrc);
}
希尔排序
/** 希尔排序-升级插入排序-用增量去切割整体待排序-使得基本有序-简单插入的升级版-就是把1换成了增量 */
private static void shellSort(int[] src) {
printArray("----------------shellSort----------", src);
int increment = 8;// 为待排序的数据长度
int i, j;
do {
increment = increment / 3 + 1;// 与简单插入排序相比把1替换为 increment,减少了排序次数.
printInt("------------------increment=" + increment);
for (i = increment + 1; i <= 8; i++) {
printInt("-----------------i=" + i);
if (src[i] < src[i - increment]) {// 将src[i]插入有序增列表中 这里就是直接插入,
src[0] = src[i];// 暂存
for (j = i - increment; j > 0 && src[j] > src[0]; j -= increment) {
src[j + increment] = src[j];// 空出插入位置
printArray("insert one:", src);
}
src[j + increment] = src[0];
printArray("insert two:", src);
}
}
} while (increment > 1);
printArray("----------------shellSort----------", src);
}
并归排序
/** 并归排序-用递归的思想-递归和树是一样的 执行顺序和前序遍历一样,从左到右 */
private static void mergeSort(int[] src) {
printArray("mergeSort-src:", src);
MSort(src, src, 0, src.length-1);
}
private static void MSort(int[] SR, int[] TR, int low, int high) {
int mid;
int[] NewTR = new int[high+1];
if (low == high) {
TR[low] = SR[low]; //这个是退出递归条件,否则就会无限递归,当递归到只有1个元素时就退出。
} else {
mid = (low + high) / 2;
MSort(SR, NewTR, low, mid);
MSort(SR, NewTR, mid + 1, high);
Merge(NewTR, TR, low, mid, high);
}
}
private static void Merge(int[] SR, int[] TR, int low, int mid, int high) {
int j, k, l;
for (j = mid + 1, k = low; low <= mid && j <= high; k++) {
if (SR[low] < SR[j]) {
TR[k] = SR[low++];
} else {
TR[k] = SR[j++];
}
}
if (low <= mid) {
for (l = 0; l <= mid - low; l++) {
TR[k + l] = SR[low + l];
}
}
if (j <= high) {
for (l = 0; l <= high - j; l++) {
TR[k + l] = SR[j + l];
}
}
}
快速排序
/** 快速排序-冒泡排序的升级版-把大的待排序切割成小的 */
private static void quickSort(int[] src) {
qSort(src, 0, src.length - 1);
}
private static void qSort(int[] des, int low, int high) {
int pivot;
if (low < high) {
pivot = partition(des, low, high);// 枢轴
printInt("qSort--pivot=" + pivot );
qSort(des, low, pivot - 1);
qSort(des, pivot + 1, high);
}
}
/** 大的数据分割成小的部分 */
private static int partition(int[] des, int low, int high) {
int value;
value = des[low];
while (low < high) {
while (low < high && des[high] >= value) {
high--;
}
swap(des, low, high);
while (low < high && des[low] <= value) {
low++;
}
swap(des, low, high);
}
return low;
}