线性表之顺序存储结构与链式存储结构 及 应用
Posted 踩踩踩从踩
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性表之顺序存储结构与链式存储结构 及 应用相关的知识,希望对你有一定的参考价值。
前言
我们常用的线性表是顺序存储结构和链式存储结构表示,是最基本、最简单、也是最常用的一种数据结构;一个线性表是由n个相同特性的数据的有限序列;比如java中的数组 ,链表;所以学习这两种结构表示是非常必要的。
线性表结构特点
- 均匀性 数据元素是不同的,对于同一线性结构的各种数据元素必定有相同的数据类型和长度
- 有序性 各数据元素在线性表中的位置只取决于它们的序号,数据元素之前的相对位置是线性的,即存在唯一的“第一个“和“最后一个”的数据元素,除了第一个和最后一个外,其它元素前面均只有一个数据元素(直接前驱)和后面均只有一个数据元素(直接后继)。
顺序存储结构
定义
用一组地址连续的存储单元依次存储线性表的结构,它以“物理位置相邻”来表示线性表中数据元素间的逻辑关系,可随机存取表中任一元素。
- a1是a2的前驱,ai+1是ai的后继,a1没有前驱,an没有后继,n为线性表的长度,若n==0时,则线性表为空,这个长度n也就是我们平常size的概念,每个线性表,一定会有size的概念‘
- 这里还有个注意点,比如arraylist中实现,不要只局限于基本数据类型,可以存object类型的 ,这下面的
class ArrayList{
Student[40];
int size;
}
比如上图的结构也是顺序结构
插入与删除
插入某个元素,一定是会 将后面数据进行移动 复制, 就像 arraylist中 下面进行插入
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
删除某个元素,也是需要 将后面元素进行复制
优缺点
优点:
尾插效率高,支持随机访问。
缺点:
中间插入或者删除效率低。
应用:
数组
ArrayList
利用顺序结构的蛮力排序(蛮力法)
针对数据量少的排序方式 ,速度快;但数据量大了过后,时间会降低;
蛮力法(brute force method,也称为穷举法或枚举法)
是一种简单直接地解决问题的方法,
常常直接基于问题的描述,
所以,蛮力法也是最容易应用的方法。
但是,用蛮力法设计的算法时间特性往往也是最低的,
典型的指数时间算法一般都是通过蛮力搜索而得到的 。(即输入资料的数量依线性成长,所花的时间将会以指数成长)
这种算法,在数据量很少的情况下,速度是最快的;也就是我们常说的冒泡法和快速排序法;
应用:数据量足够小,比如斗牛游戏的牌面排序 ;也就是 n一般小于5的情况
冒泡排序算法
第一轮进行 只要当前点大于(或者小于)下个结点,就进行交换,就能取到一个最大(最小)的结点,这样不断循环
实现代码
for(int i=array.length-1;i>0;i--) {
boolean flag=true;
for (int j = 0; j < i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag=false;
}
}
if(flag){
break;
}
}
- 上面的代码 分为第一轮,首先 冒泡到 array.length-1
for(int i=array.length-1;i>0;i--) {
- 第二轮 需要在剩余的 不断交换
for (int j = 0; j < i; j++) {
- 这样的时间复杂度 的就是 n(n-1)/2 , 具体就是 n ,n-1,n-2.....1 相加
- 针对小数据量,做了个flag进行优化, 数据已经排列好时,就先退出不走后面逻辑
这里做的一个 花色和点数进行比较排序数据 利用对象进行排序
- 首先做一个 cards 需要排序的 方式 利用comparable ;
public class Cards implements Comparable{
public int pokerColors;//花色
public int cardPoints;//点数
public Cards(int pokerColors, int cardPoints) {
this.pokerColors = pokerColors;
this.cardPoints = cardPoints;
}
//提供一个方法,用来比较对象的大小
@Override
public int compareTo(@NonNull Object o) {
Cards c=(Cards)o;
if(this.cardPoints>c.cardPoints){
return 1;
}else if(this.cardPoints<c.cardPoints){
return -1;
}
if(this.pokerColors>c.pokerColors){
return 1;
}else if(this.pokerColors<c.pokerColors){
return -1;
}
return 0;
}
@Override
public String toString() {
return "Cards{" +
"pokerColors=" + pokerColors +
", cardPoints=" + cardPoints +
'}';
}
}
- 进行冒泡排序数据
for(int i=array.length-1;i>0;i--) {
boolean flag=true;
for (int j = 0; j < i; j++) {
if (array[j].compareTo(array[j+1])>0) {
Cards temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag=false;
}
}
if(flag){
break;
}
}
冒泡法应用场景,在数据很多已经排序完成,则使用冒泡效率是非常高的
选择排序算法
该算法是快排的基础,理解快排,一定要理解选择排序;
第一轮进行 选择一个基准结点一般为0结点,遍历数组,一旦遇到比他小(大)进行指针下标交换,第一轮下来,就能找到最小的点的指针,然后与基准点进行交换,基准点就能找到最小的数据
具体的代码
public static void selectSort(int[] array){
for(int i=0;i<array.length-1;i++) {
int index = i;
for (int j = i+1; j < array.length; j++) {
if (array[j] < array[index]) {
index = j;
}
}
//{1,2,5,8,3,9,4,6,7};
if(index!=i) {//如果已经是最小的,就不需要交换
int temp = array[index];
array[index] = array[i];
array[i] = temp;
}
}
}
针对蛮力法的应用,一般是小于5的数据可以使用,如果数据量大,不使用该种算法
链表式存储结构
线性表下定义链式存储结构
种类
- 单链表
单链表中基本单位为节点,而每个节点 分为数据域和指针域;而指针域指向的是下个节点的下标;数据域则可以代表很多东西 包括数据,还有其他属性
针对插入和删除节点的情况
这就是单向链表的删除和添加节点的过程
单链表的应用(链式奇数排序对麻将进行排序)
解决思路
创建 对应的麻将对象
public class Mahjong {
public int suit;//筒,万,索
public int rank;//点数 一 二 三
public Mahjong(int suit, int rank) {
this.suit = suit;
this.rank = rank;
}
@Override
public String toString() {
return "("+this.suit+" "+this.rank+")";
}
}
需要分别按花色和大小进行排序
//先对点数进行分组
LinkedList[] rankList=new LinkedList[9];
for (int i=0;i<rankList.length;i++){
rankList[i]=new LinkedList();
}
- 第一次处理按大小 分成9个点数分为九段链表
//把数据一个一个的放入到对应的组中
while(list.size()>0){
//取一个
Mahjong m=list.remove();
//放到组中
rankList[m.rank-1].add(m);
}
//把9个组合到一起
for (int i = 0; i < rankList.length; i++) {
list.addAll(rankList[i]);
}
- 第二次按花色进行拆分
//先花色数进行分组
LinkedList[] suitList=new LinkedList[3];
for (int i=0;i<suitList.length;i++){
suitList[i]=new LinkedList();
}
//把数据一个一个的放入到对应的组中
while(list.size()>0){
//取一个
Mahjong m=list.remove();
//放到组中
suitList[m.suit-1].add(m);
}
//把3个组合到一起
for (int i = 0; i < suitList.length; i++) {
list.addAll(suitList[i]);
}
先可以按花色在按点数进行分组,都是可以的,主要是按单链表顺序排序的结构
- 双链表
这里的查找删除,主要是可以借助于linkedlist的源码,也是双向链表的
/**
* 在最后添加
* @param e
*/
private void linkLast(E e) {
Node<E> newNode = new Node<E>(last, e, null);
Node<E> l = last;
last = newNode;
if (l == null) {
first = newNode;
}else {
l.next = newNode;
}
size ++;
}
/**
* �在index的位置上添加一个元素
* @param index
* @param e
*/
public void add (int index, E e) {
if(index < 0 || index >size) {
return;
}
if (index == size) {
linkLast(e);
} else {
Node<E> target = node(index);
Node<E> pre = target.prev;
Node<E> newNode = new Node<E>(pre, e, target);
// pre.next = newNode;
// pre = newNode;
//要考虑index=0时的情况
if(pre == null) {
first = newNode;
} else {
pre.next = newNode;
}
pre = newNode;
size++;
}
}
主要注意点,在添加 删除节点时,和单链表的区别 ,要考虑 前后节点都要修改
参考分析 可以看看我的linkedlist的源码分析
Java 集合深入理解 (二) :LinkedList链表源码研究,及双向队列如何实现
- 单向循环链表
和单向循环链表就是,后指针指向前面个
- 双向循环链表
而对于双向循环链表,则 指针修改的
总结
整个线性表的两种数据结构,各有各的应用场景,各有优缺点,主要在我们java中可以使用到,我们在应用中,各个场景下实现。
以上是关于线性表之顺序存储结构与链式存储结构 及 应用的主要内容,如果未能解决你的问题,请参考以下文章