一丶十种数据结构相关特性和使用
开始努力认真的学习,看看自己能达到哪个水平
常见的十种最基本的数据结构:数组、链表、栈、队列、散列表、跳表、图、树、堆、字典树
1.数组(java中的HashMap底层就是数组加链表加红黑树的形式,链表长度大于8转换为红黑树,更根据统计学原理,链表长度超过8的情况很低,这是就可以忽略红黑树所占空间比链表大的影响,相对于链表而言。个人感觉:普通算法时间换空间或者空间换时间,顶级的算法,时间和空间可以极大的缩小)
固定存储空间(空间方面)在最初的设计层面上,数 组是依赖内存分配形成的,在使用数组前必须先为它申请空间。这使得数组这种数据结构有了下的特性:(四种特性的实现原理有待查找资料)
①一个数组占据的存储空间大小固定,不能改变。(联想:所以在java的数组中,当数组需要扩容的时候,是新建一个新的长度更大的数组,并把之前数组的数据全部复制过去)
②所占据的存储空间是专用的,不能被其他信息占据。
③所占据的存储空间是连续的,中间不能间隔其他信息
④数组中的各个元素可以用数组名和下标直接访问
按数组下标取值的时候,a[i] = *(a + i)计算机需要知道待访问内存的内存地址是多少,数组名就是数组存放的首地址,根据数据类型以及下标求出偏移量就可以访问到对应位置的数据。
优点:
①方便。要读要写都很直接。无论多长的数字,要访问其中的一个元素,只要知道它的下标,就能一部到位,直接访问对应的样式。
缺点:
①占内存空间。开始时就要把以后所有用到的空间都申请下来,就算长时间里装不满,也不许存入其他信息。(数组性第②点),空置的空间浪费了。
②修改困难。理论上讲,一个数组如果没有装满,那么所有的空置位置都应该在尾部,而不是到处乱空。如果给数组中加入新元素,则只能加在尾部,如果要插入到中间位置,就有一些元素被移动。反过来,如果删掉一个元素,也得把后面的再往前挪一位。
连续存储的关系,所有的这些限制,都是因为数组是连续的一快存储空间,且个元素由下标标识引起的。如果不遵守这些限制,数组相应的好处也就得不到了。
数组设计到的排序算法:冒泡排序,选择排序,插入排序,快速排序,合并排序,随机排序,统计排序
①冒泡排序:法是把较小的元素往前调或者把较大的元素往后调。这种方法主要是通过对相邻两个元素进行大小的比较,根据比较结果和算法规则对该二元素的位置进行交换,这样逐个依次进行比较和交换。
优点:稳定(假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。); 缺点:慢,每次只能移动相邻两个数据。
public static void bubbleSort(int[] array){
int length = array.length;
//要完成排序总共需要比较的循环的次数
for(int i = 0;i< length-1;i++){
//length-i-1每次比较的最后一位,每循环一次后,就有一个数字排好了位置
for(int j = 0;j < length - i-1;j++){
//决定是升序还是降序排列,把较大的数字往后交换为升序,把较小的数组往后交换为降序
if(array[j]>array[j+1]){
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
}
选择排序:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在最前或最后,后面每一次选出来的依次排序,直到全部待排序的 数据元素排完
优点:空间复杂度为O(1) 缺点:效率不是很好,实际中很少使用
public static void selectSort(int[] array){
int length = array.length;
//要完成排序总共需要比较的循环的次数
for(int i = 0;i< length-1;i++){
//这里是每次循环挑选出最小的依次放在数组前面,最后完成排序
for(int j = i+1;j < length;j++){
//决定是升序还是降序排列,把最大最小的数字选出来放在应该在的位置
if(array[i]>array[j]){
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
}
}
插入排序:将第一个元素标记为已排序,对于每个未排序元素X“提取”元素X对于j = lastSortedIndex降至0,如果当前元素j> X, 将排序的元素向右移动1
中断循环并在此处插入X
优点:稳定,快。对于已经有一定顺序的数组,排序速度很快,因为只要找到比标记为已排序的数小的时候,这一轮循环就结束了–升序排序时,只要找到比标记为已排序的数大的时候,这一轮循环就结束了–降序排序时。
缺点:比较次数不一定
public static void insertSort(int[] array){
//数组的长度
int length = array.length;
//要完成排序总共需要比较的循环的次数(和它之前的所有数比较)
for(int i = 1;i< length;i++){
//标记为已排序的元素(下标为 1-->length-1,第一位数前面没有数可以看成是已经排序的)
int temp = array[i];
//每个数都和它之前的所有数进行一个比较(第一位数前面没有数可以看成是已经排序的)
for(int j = i-1;j >= 0;j--){
//决定是升序还是降序排列,把数字插入到前一个它小后一个数比它大的位置(升序),
//把数字插入到前一个它大后一个数比它下的位置(降序)
//比选定的已排序大的时候,该数往后移动一位。(排序的数字已经取出,可以覆盖原有的位置)
if(temp<array[j]){
int more = array[j+1];
array[j+1] = array[j];
array[j] = more;
}else {
array[j+1] = temp;
break;
}
}
}
}
快速排序:采取的是分而治之的思想,先取一个基准数,将小于于基准数的的放在基准数的左边,比它大的放在基准数的右边(升序排序,降序排序相反),因为这个基准数左边是不小于它,右边是大于它的,所以现在这个基准数就找到了排序后它应该在的位置。然后基准数左右两边分别循环这个过程,直到整个序列有序。
优点:极快,数据移动少
缺点:不稳定
public static void quickSort(int[] array) {
//数组的长度
int length;
//要判断array为null,长度为0,1的情况不需要进行排序
if (array == null || (length = array.length) == 0 || length == 1) {
return;
}
// 基准值设置为数组的第一个数
quick(0, length - 1, array);
}
public static void quick(int left, int right, int[] array) {
// 升序排列
//到左指针大于右指针时递归结束
if (left > right) {
return;
}
// 双指针,分别从右往左比它小,和从左往右查询比他大,
int i = left;
int j = right;
// 基准值
int base = array[left];
// i<=j意味着这个分区还没有排序左右分区完。
while (i != j) {
// 先从右往左找,找到比基准数小的,并且i<j
//这里必须先从右往左找,因为我们需要的位置是比基准值小的最大下
//标的数,因为先从右往左找一个区间的最后一次比较j停在的是比基
//准数小的数的位置。如果是先从左往右找i会停在比基准数大的值的
//最小下标的位置
while (array[j] >= base && i < j) {
j--;
}
// 先从左往右找,找到比基准数大的,并且i<j
while (array[i] <= base && i < j) {
i++;
}
if (i < j) {
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
// 将基准值和比它小的数的下标的最大一位交换(例:基准值是8;左右分区后的数组{8,2,4,5,7,12,45,24}
// 当8与比它小的下标最大的一位交换后,数组为(2,4,5,7,8,12,45,24),就达到了左边都是比8小,右边都是比8大的效果)
array[left] = array[i];
array[i] = base;
// 递归排序左右这两个分区
quick(left, i - 1, array);
quick(i + 1, right, array);
}
总结:数组因为存储空间是连续的,所以想要查找数组的第n个数的时间复杂度为o(1),List添加数据只要不是在尾部进行,时间复杂度都为O(n),在其余位置添加都需要移动数据位置,删除和添加同理。数组是很多复杂数据结构的基础类型。对于数组几种不同的排序方法,他们优劣都必须要熟练掌握,主要从稳定性和时间,空间这个三个方面。
2.链表 一种物理上可以是非连续、非顺序的存储结构,通过指针链接次序实现的,想对于数组的顺序存储,对空间的要求就没那高了,数组必须要一段符合数组大小的连续的存储空间,而链表不同,逻辑上连续即可。链表中中的每一个单元除了存储自身数据之外,还存储了指向下一个数据的指针。(单向链表是最基本的数据结构类型,其余的什么双向链表,循环链表,单向循环链表,双向循环链表都是以单向列表而来,操作也基本类似,这里就不过多的描述)
Object a{
//存储的是自身的数组
private Object data;
//存储的是到下一个数据的指针
private Object next;
}
对于链表的使用,需要的掌握的有,链表的翻转、添加、删除及链表有环的时候的一些操作。
本文探讨了十种基本数据结构中的数组和链表,重点讲解了数组的固定存储空间特性、优缺点以及涉及的排序算法,如冒泡排序、选择排序和快速排序。同时,介绍了链表的非顺序存储结构及其在空间需求上的优势,以及链表的基本操作。

被折叠的 条评论
为什么被折叠?



