单向链表
有过数据结构的基础的同学应该都知道,一个链表是由若干个节点组成的,而每一个节点由两部分组成,一部分是自己本身所储存的数据,另一部分则是指向下一个节点的节点对象。这刚听起来有点别扭,因为这就相当于每一个节点都存储另一个节点的对象,这个对象指向的是下一个节点。大概的原理图如下:
在这里我们把A(节点本身A的简称)称作头节点(链表里的基本操作差不多都是与头节点有关的),看了这个原理图以后我相大家都一目了然,在这张图里A的指向B,B指向C。链表就是由这样若干个节点组成的。
看到这里不知道大家有没有发现一个问题,那就是链表里的最后一个节点C里的对象指向哪里呢?
其实也很简单,就相当于如果只有一个节点的话,我们只需要让它直接指向null就好了。
明白了链表的组成是由节点组成的以后,我们就可以对其进行操作了。我们都知道,一般的链表都有最基本的增删查改操作。
那么往里面添加数据的话就是添加一个节点 (注意:在这里添加的顺序是从右往左进行的),在这里我们每添加一个节点就把头节点赋给新添加的那个节点。然后再把头节点的对象指向下一个节点。删除的话就更简单了,只需要把数据取出,然后再将头节点里的节点对象指向被删除节点的下一个节点…还有许多的操作都是在头节点上做文章的,在这里我就不一一赘述了。
**添加数据:**在添加数据之前,我们需要首先判断当来一个数据的时候,我的链表是否已经含有节点。如果有的话我们就需要新建一个节点,然后我们将新来的数据添加到新创建的这个节点,再将其指向已经存在的上一个节点,并将新建的这个节点赋为头节点。如果没有的话那就更好办了,直接新建一个节点然后将数据存储进去,并将它赋为头节点。
简单来说就是三步:
**1.判断是否已经存在节点
2.如果没有就新建节点,有也要新建,然后存储数据。
3.将新建的节点赋为头节点,并其指向已经存在的上一个节点(如果链表内只有一个节点的话就指向null)
明白了以上三步以后那就简单了,接下来我们利用代码来实现:
/**
* 在链表里添加数据.
* @param s 输入的数据
* @return 返回的数据
*/
public Object addData(String s){
Node newNode = new Node(); //新建一个节点(无论有无节点都要新建)
if(size==0){ //如果链表内没有节点
newNode.data = s; //将来的数据添加到新建的节点内
head = newNode; //将新建的节点赋为头节点
}
else{
newNode.data = s; //将来的数据添加到新建的节点内
newNode.next = head;//指向上一个数据
head = newNode;//将新建的节点赋为头节点
}
size++;
return head.data;
}
**删除数据:**链表里删除数据的操作很简单。但是我们需要注意,在删除数据以后被删除数据的这个节点也要删除。被删除以后,要将链表的长度-1。要知道数据是和节点是“共存亡”的。
然而实现这个操作也非常简单,在上面我们也说过了,节点是一个指向一个的。如果我们要删除一个节点的话,那么只需要将指向被删除的这个节点不要指向删除的节点就好啦,跳过它,直接指向它的下一个节点。这样被删除的的节点就会被空出来不被使用,那么Java内存在的“回收站”会自动将其删除。
/**
* 在链表里删除指定数据
* @param obj 输入指定数据进行删除
* @return 若删除成功则为真.反之则为假.
*/
public boolean DeleteData(Object obj){
Node forward = head;
Node current = head;
int tempSize = size; //链表长度
if(tempSize==0){
return false;
}
while(current.data!=obj){
if(current.next == null)
return false;
else{
forward = current;
current = current.next;
}
}
size--;
return true;
}
**查找数据:**在链表里查找指定数据,同样的先从头节点开始寻找,若找到了则返回该节点。若没找到则寻找下一个节点
/**
* 在链表内查找指定的数据,若查找到了则返回该节点
* @param data 输入需要查找的指定数据
* @return 存储该数据的节点
*/
public Node getData(Object data){
Node temp = head;
int fake = size;
// if(fake==0)
// return null;
// else{
// for(int i = 0;i < fake;i++){
// if(temp.data!=data)
// temp=temp.next;
// else
// break;
// }
// return temp;
// }
// }
if(fake==0)
return null;
while(fake!=0)
{
if(temp.data.equals(data))
{
break;
}
temp = temp.next; //寻找下一个节点
fake--;
}
return temp;
}
小结一下:链表存储数据是无序的,和数组比起来它的优点是在进行删除和增加的时候更加方便,但是在修改数据方面稍有欠缺,每种数据结构都有自己的优缺点,至于再怎样选择更好的数据结构,则需要根据实际项目来选择。
下面是我的整体代码:
package twb2019_07_18;
/**
* 用头插法简单的实现一个单向链表
*/
public class SingleLinknode {
public Node head; //头节点
public int size = 0; //链表的长度
public class Node{
public Node next; //指向上一个节点
public Object data; //存储的数据
}
/**
* 在链表里添加数据.
* @param s 输入的数据
* @return 返回的数据
*/
public Object addData(String s){
Node newNode = new Node(); //新建一个节点(无论有无节点都要新建)
if(size==0){ //如果链表内没有节点
newNode.data = s; //将来的数据添加到新建的节点内
head = newNode; //将新建的节点赋为头节点
}
else{
newNode.data = s; //将来的数据添加到新建的节点内
newNode.next = head;//指向上一个数据
head = newNode;//将新建的节点赋为头节点
}
size++;
return head.data;
}
/**
* 在链表里删除指定数据
* @param obj 输入指定数据进行删除
* @return 若删除成功则为真.反之则为假.
*/
public boolean DeleteData(Object obj){
Node forward = head;
Node current = head;
int tempSize = size; //链表长度
if(tempSize==0){
return false;
}
while(current.data!=obj){
if(current.next == null)
return false;
else{
forward = current;
current = current.next;
}
}
size--;
return true;
}
/**
* 在链表内查找指定的数据,若查找到了则返回该节点
* @param data 输入需要查找的指定数据
* @return 存储该数据的节点
*/
public Node getData(Object data){
Node temp = head;
int fake = size;
// if(fake==0)
// return null;
// else{
// for(int i = 0;i < fake;i++){
// if(temp.data!=data)
// temp=temp.next;
// else
// break;
// }
// return temp;
// }
// }
if(fake==0)
return null;
while(fake!=0)
{
if(temp.data.equals(data))
{
break;
}
temp = temp.next; //寻找下一个节点
fake--;
}
return temp;
}
/**
* 更具指定位置的下标修改数据
* @param index 需要修改的节点的下标.
* @param object 需要修改的数据.
*/
public void modifyData(int index,Object object){
Node temp = head;
// int fake = size;
if(index == 0)
System.out.println("下标必须大于0!");
for(int fake = size;fake>0;fake--){
if(fake == index){
temp.data = object;
}
temp = temp.next;
}
}
/**
* 显示链表里的所有数据
*/
public void displayAllDtat(){
Node temp = head;
int fake = size;
while(fake!=0)
{
System.out.print("["+temp.data+"]"+"->");
temp = temp.next;
fake--;
if(fake==1){
System.out.println("["+temp.data+"]");
break;
}
}
}
/**
* 返回头节点的数据
* @return 返回的头节点内的数据
*/
public Object getHeadNode(){
return head.data;
}
}
下面测试一哈子:
public class testNode {
public static void main(String[] args){
SingleLinknode sl = new SingleLinknode();
//增加操作
sl.addData("a");
sl.addData("b");
sl.addData("c");
sl.addData("d");
sl.addData("e");
//显示操作
sl.displayAllDtat();
System.out.println(sl.DeleteData("a")); //删除操作
System.out.println(sl.size);
sl.displayAllDtat();
System.out.println(sl.getData("c")); //查找操作
sl.modifyData(3,"a"); //修改操作
sl.displayAllDtat();
}
}
显示结果:
好了,今天就先到这里,如果大家还有什么问题可以和我一起讨论一哈,贴一下联系方式,先吃个饭,有点饿~
QQ:1027759481
VX:a1027759481