标签:常见 false 问题 null 码云 class strong for 避免
列表集合比栈和队列更一般化,可以在列表的中间和末端添加和删除元素。
有序列表是基于列表中元素的某种特性的。对于任何已添加到有序列表中的元素,只要给定了元素的关键值,同时列表已定义了元素的所有关键值,那么它在列表中就会有一个固定的位置。
无序列表中各元素的位置并不基于元素的任何内在特性。列表中的元素是按照特殊顺序放置的,只不过这种顺序与元素本身无关。
索引列表的各元素间不存在能够决定他们在列表中的顺序的内在关系。每个元素都能够从一个数字索引值得到引用,该索引值从列表头开始从0连续增加直到列表末端。
索引值与数组的根本区别:索引列表的索引值总是连续的?
Java集合API提供的列表类主要是支持索引列表。Java API没有任何直接实现的有序列表。
Serializable接口的作用是实现串行化,为了使某个对象能使用串行化进行存储。
Java 序列化技术可以将一个对象的状态写入一个Byte 流里(串行化),并且可以从其它地方把该Byte 流里的数据读出来(反串行化)。
只有Comparable对象才能存储在有序列表。
接口可以用来派生其它接口,子接口包含父接口的所有的抽象方法
接口名可以用来声明一个对象引用变量。一个接口引用可以用来引用实现了该接口的任意类的任意对象。
接口允许创建多态引用,其中被调用的方法是基于被引用时的特定对象的。
问题1解决方案:书上说的索引列表与数组的根本区别是索引列表的索引值是连续的。那么,数组的索引值就不连续么?可以从0开始,下一个直接到5么?仔细想想是不很可能的,那么书上的话是什么意思呢?网上并没有相关的答案,所以我想了一下觉得指的是数组可以在容量允许的前提下跳跃式的往数组内添加元素,可以在0索引值处添加元素,然后在5索引值处添加元素,中间的索引值内都为零。而所以索引列表不同,只能连续的往里面添加,不能中间出现断档。
- 索引列表为它的元素维护了一段连续的数字索引值。
问题2解决方案:队列用环形数组的原因是只在一头出另一头进,而列表的添加方法比较多,其中就要求在中间进行添加,此外删除的时候也要求既可以删头又可以删尾的。所以,使用环形数组并不方便,头部变量和尾部变量都在动,插中间会更麻烦。
问题1的解决方案:有序列表与无序列表在添加的方法下有很大的不同,有序列表的添加直接按元素的内在顺序进行排列,而无序列表的就比较任意可以根据用户的想法进行。此外,有序列表要求的是只有Comparable对象才可以存储在有序列表中。
数组表示有序列表的添加
public void add(T element) {
if (!(element instanceof Comparable)) {
throw new NonComparableElementException("OrderList");
}
Comparable<T> comparableElement = (Comparable<T>) element;
if (size() == list.length)
expandCapacity();
int scan = 0;
while (scan < rear && comparableElement.compareTo(list[scan]) > 0)
scan++;
for (int shift = rear; shift > scan; shift--)
list[shift] = list[shift - 1];
list[scan] = element;
rear++;
modCount++;
}
链表表示有序列表的添加
public void add(T element) {
LinearNode<T> node = new LinearNode(element);
LinearNode<T> temp1 = null,temp2 = head;
while(temp2 != null && node.compareTo(temp2.getElement())> 0){
temp1 = temp2;
temp2 = temp2.getNext();
}
if(temp1 == null){
head = tail = node;
}
else{
temp1.setNext(node);
}
node.setNext(temp2);
if(node.getNext() == null)
tail = node;
count++;
modCount++;
}
通过compareTo方法来进行比较,通过循环遍历队列元素来判断大小,然后数组把添加的索引值后面的元素进行后移,链表进行插入操作就行。但是,数组需要判断容量大小,以及循环次数不是数组的容量而是元素的总量;链表需要确定添加的元素之前链表是否有内容,没有内容的话直接头结点等于尾节点等于添加元素,有内容的话需要把后面的内容接上。
数组表示无序列表的添加--头插
public void addToFront(T element) {
if (size() == list.length)
expandCapacity();
for (int shift = rear; shift > 0; shift--)
list[shift] = list[shift - 1];
list[0] = element;
rear++;
modCount++;
}
数组表示无序列表的添加--尾插
public void addToRear(T element) {
if (size() == list.length)
expandCapacity();
list[rear] = element;
rear++;
modCount++;
}
数组表示无序列表的添加--目标元素后面
public void addAfter(T element, T target) {
if (size() == list.length)
expandCapacity();
int scan = 0;
while (scan < rear && !target.equals(list[scan]))
scan++;
if (scan == rear)
throw new ElementNotFoundException("UnorderedList");
scan++;
for (int shift = rear; shift > scan; shift--)
list[shift] = list[shift - 1];
list[scan] = element;
rear++;
modCount++;
}
链表表示无序列表的添加--头插
public void addToFront(T element) {
LinearNode<T> node = new LinearNode<T>(element);
LinearNode<T> temp = head;
if(isEmpty())
head = node;
else {
node.setNext(head);
while(temp.getNext() != null){
temp = temp.getNext();
}
tail = temp;
head = node;
}
count++;
modCount++;
}
链表表示无序列表的添加--尾插
public void addToRear(T element){
LinearNode<T> node = new LinearNode<T>(element);
if(isEmpty())
head = node;
else
tail.setNext(node);
tail = node;
count++;
}
链表表示无序列表的添加--目标元素后面
public void addAfter(T element, T target) {
LinearNode<T> node = new LinearNode<T>(element);
LinearNode<T> temp = head;
if(temp == null){
head = tail = node;
}
while((temp != null)&&(temp.getElement() == target)){
temp = temp.getNext();
}
if(temp.getNext() == null){
temp.setNext(node);
tail = node;
}else{
node.setNext(temp.getNext());
temp.setNext(node);
}
count++;
modCount++;
}
无序列表的添加看似多实则比有序列表的简单多了就是进行尾插、头插、中间插三种方法。其中,尾插法相对简单,头插法需要把数组内的所有元素整体后移,遍历一遍,中间插的话要考虑插后的元素来确定后移的循环次数。问题2的解决方法:无序列表和有序列表的共有方法
- removeFirst:从列表中删除第一个元素
- 数组:需要先判断数组是否为空,不为空的话索引值为0的内容直接等于索引值为1的内容,以此循环前移。
- 链表:先判断链表内的元素的个数,如果为1直接头结点等于尾节点等于空,不为1的话直接使链表的头等于头的下一个。
- removeLast:从列表中删除最后一个元素
- 数组:在数组不为空的前提下,直接使数组索引值最大的位置内为空,计数变量减一。
- 链表:确定链表内元素的个数,如果为1直接头结点等于尾节点等于空,不为1的话就通过遍历链表,从头找到尾,确定尾部为空,倒第二为尾部。
- remove:从列表中删除某个元素
- 数组:通过find方法的辅助可以确定删除元素是否在队列中以及索引值的位置,然后在此索引值后的元素依次前移,此前数组索引值最大的位置为空。
- 链表:确定列表是否为空或仅有一个元素、元素是否在列表中、并处理删除元素是列表的末尾元素、首元素、还是中间位置。如果是删除仅有的元素就直接令头结点等于尾结点等于空,删除头元素直接令头结点等于头结点的下一个,删除尾元素就遍历到倒数第二个为尾结点,删除的是中间的元素就直接把前一个元素与后一个元素连接。
- first:查看位于列表前端的元素
- 数组:先判断数组是否有元素,再直接输出索引值为0的内容。
- 链表:先判断链表内是否有元素,再直接调出头结点的内容。
- last:查看位于列表末端的元素
- 数组:先判断数组是否有元素,再直接输出索引值最大的内容。
- 链表:先判断链表内是否有元素,再直接调出尾结点的内容。
- contains:确定列表是否含有某个元素
- 数组:通过find方法辅助就可以(在一定程度上find方法和contains方法作用相同)。
- 链表:在不为空的情况下,遍历一遍链表找寻就可以。
- isEmpty:判定列表是否为空
- 数组:判断计数变量是否为零,为零即列表为空。
- 链表:头结点等于尾结点等于空或是计数变量是否为零。
- toString:
- 数组:以计数变量的值为循环次数进行循环输出。
- 链表:从头节点开始遍历一遍到尾结点。
- 关于数组列表的find方法:通过元素与数组内每一个索引下的内容的对比,来判断索引值的方法。
- 优点:可以使其他方法变得简单易懂,也可以利用find方法来辅助其他一堆方法。
i++
与i+1
的区别i++
与i+1
的不同意义,虽然之前老师说过两者意义不同,一直没有在意,直到两者在循环的时候才发现,如果用i++
的话并不会删除目标元素,相反会把数组的末尾元素删掉;如果用i+1
的话就会把删除目标元素,数组的末尾元素不会被删掉。我觉得是在第一次循环的时候,i++
并没有起到自增的作用,而是把i索引值内的元素又放到i索引值内,导致最后一次循环的时候尾部元素的索引值是最大的,被后面的赋空语句直接删掉了。而i+1
就在循环的第一次实现了自增,使得目标元素被删掉,最大索引值和最大索引值减1存储的都是一个元素,这样在通过赋空语句就可以了。
i++
版:i+1
版:问题4解决方案:相同类型的编程项目在上学期第七章就实现过,实现Comparable接口,很多同学因为没有写implements Comparable<>直接写个方法完成而扣分,印象十分深刻。有了之前的经验,在练习这次的就没那么难,之前的是进行一重比较,题目要求的是两重比较,在系相同的情况下对课程号进行排序。直接把比较后的数值输出,然后在(有序列表)添加的方法里面融入比较的方法。但是,在上传到码云的时候看了一下别人的代码,觉得直接确定大小后输出-1、1和0三个固定的数没有差别,就没有进行修改。在用数组和链表去实现的时候,发现用数组的方法就会报错NullPointerException,找了半天也没有发现错误,后来使用链表的方法就很成功的实现了,会继续找数组的添加方法的bug的。
错误解析:检查队列前面的元素用的是first方法,size是用来判断队列里元素的个数。
第六章的内容是用数组和链表表示列表的,在一定还曾独上列表和队列、栈都有一定程度上的相似,部分代码完全可以之前编写的,唯一觉得比较恶心的就是在添加的过程中就直接被排序。通过这几章学的内容,对链表和数组有了更多的认识,应用起来也比较顺手。勤能补拙,多联系多尝试总没有错的。
20172305 2018-2019-1 《Java软件结构与数据结构》第四周学习总结
标签:常见 false 问题 null 码云 class strong for 避免
原文地址:https://www.cnblogs.com/sanjinge/p/9751514.html