一、链表的初步认识:
从上一篇中,我们已经知道了顺序表,但是从顺序表的插入和删除来看,是比较麻烦的,时间复杂度为O(n),因此这里就有了另外一种结构:链表。链表就是逻辑结构上连续,但是物理结构上不一定连续。对于链表来说,一共有8种链表。
1 单向和双向的
在这其中,第一种是单向的,也是没有头结点的,就类似有傀儡节点;第二种是双向的,也是有类似的傀儡节点,但是要注意头和尾节点,中间的插入和删除需要注意。
2 带头或者不带头的
3 循环或者不循环的
分类别就是上面的三种类别,组合起来就是8种。
但是用的最多的还是:
无头单向非循环的链表,结构:
二:链表的实现
老规矩,咱就是说,直接上代码
首先是定义节点:
class LinkNode{
public int data;
public LinkNode next;
public LinkNode(int data){
this.data=data;
}
}
(1)addFirst(int data):实现链表的头插,这个还是基表简单的,思想就是把新节点的next域指向最开始的头结点就行,其最后实现的是倒序
public void addFirst(int data){
//头插法的本质就是:把新节点以头节点为依靠,插在头结点的前面,即依靠头来插入
//首先的把数据用节点包装起来
LinkNode linkNode=new LinkNode(data);
linkNode.next=head;
//然后再把head移到新节点处
head=linkNode;
}
(2)addLast(int data):就是按照正常的顺序进入链表,只是要注意:需要再定义一个节点指针来遍历链表,见代码
public void addLast(int data) {
//就是以尾巴(最后一个节点)为依据来插入,那么就需要找到最后一个节点
//先包装data
LinkNode linkNode = new LinkNode(data);
if (this.size() == 0) {
head = linkNode;
} else {
LinkNode temp = head;
while (temp.next != null) {
temp = temp.next;
}
//这里以找到最后一个节点结束
temp.next = linkNode;
}
}
(3)求链表的大小:遍历一定要找一个节点指针,然后遍历
//得到单链表的长度
public int size(){
int count=0;
LinkNode temp=head;
while(temp!=null){
count++;
temp=temp.next;
}
return count;
}
(4)判断下标是否合法:下标和顺序表一样,不能小于0,不能超过长度,但是链表没有下标
public boolean isIndex(int index){
if(index<0||index>this.size()){
return false;
}
return true;
}
(5)addIndex(int index,int data):把data元素添加到index下标的位置
public boolean addIndex(int index,int data){
if(isIndex(index)==false){
return false;
}
else{
//先包装
LinkNode linkNode=new LinkNode(data);
if(index==0){
addFirst(data);
}
if(index==this.size()){
addLast(data);
}
else {
LinkNode temp=head;
for(int i=0;i<index-1;i++){
temp=temp.next;
}
//这里以index-1的下标节点结束
linkNode.next=temp.next;
temp.next=linkNode;
}
}
return true;
}
(6)contains(int key):判断链表中是否含有key元素
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key){
LinkNode temp=head;
while(temp!=null){
if(temp.data==key){
return true;
}
temp=temp.next;
}
return false;
}
(7)remove(int key):删除第一次遇到key的元素,注意在这里我们必须注意要找到该元素的前一个位置,于是temp.next.data,而不是temp.next
public void remove(int key) {
if(head.data==key){
head=head.next;
}
else{
LinkNode temp=head;
for(int i=0;i<this.size()-1;i++){
if(temp.next.data==key){
temp.next=temp.next.next;
break;
}
temp=temp.next;
}
}
}
(8)removeAllKey(int key):删除所有值为key的元素,和remove的区别就是找到了但是没有break退出
//删除所有值为key的节点
public void removeAllKey(int key){
if(head.data==key){
head=head.next;
}
LinkNode temp=head;
for(int i=0;i<this.size()-1;i++){
if(temp.next.data==key){
temp.next=temp.next.next;
}
temp=temp.next;
}
}
(9)display():打印链表,遍历即可
public void display(){
LinkNode temp=head;
while(temp!=null){
System.out.print(temp.data+" ");
temp=temp.next;
}
System.out.println("\n");
}
(10)clear():清空链表,那么
public void clear(){
LinkNode temp=head;
while(temp!=null){
temp=temp.next;
head=null;
head=temp;
}
}
最后,链表的基本操作就结束了,本节一直都用的不带头结点的非循环链表来讲的,下次出栈、队列、二叉树.....,方便以后的复习,所以点赞关注起来吧。