java的单向链表的实现以及反转是很多面试官喜欢出的题目,java的链表结构是什么样的?
链表是由一个指向下一个节点的next指针,以及一个node节点。
链表的操作也是很有局限性的,查找元素只能从头节点一直往下,直达找到对应的节点为止。
链表的反转未采用递归是为了更好的理解链表的操作以及链表的查询原理
根据链表的定义我们将操作划分为四大类:插入,删除,查找,替换。
单项链表的实现
class LinkNode<T> {
private Node head;//头结点
private int count=0;//结点数目
private int foot;//相当于内部节点的index
private class Node{//内部类实现外部方法的桥梁
private T data;
private Node next;
public Node(T data){
this.data=data;
}
private void add(T value){
if(this.next==null){
this.next=new Node(value);//添加新节点
}else{
this.next.add(value);//递归到末尾
}
}
private void remove(Node privious,int index){//@privious 目标节点的上一个节点
if(LinkNode.this.foot++==index){//即使判断当前节点的索引是否等于指定节点,foot外部类指定。
privious.next=this.next;
this.next=null;
LinkNode.this.count--;
return;
}else{
this.next.remove(this,index);//递归到指定节点
}
}
private void remove(Node previous,T data){//删除
if(this.data.equals(data)){
previous.next=this.next;
this.next=null;
LinkNode.this.count--;
}else {
if (this.next != null) {
this.next.remove(this,data);
}else{return;}
}
}
private void replace(T oldData,T newData){//替换
if(this.data.equals(newData)){
this.data=newData;
}else{
this.next.replace(oldData,newData);
}
}
public void replace(int index,T newData){
if(LinkNode.this.foot++==index){
this.data=newData;
}else this.next.replace(index,newData);
}
public T get(int index){//获取
if(LinkNode.this.foot++==index){
return this.data;
}
else{
return this.next.get(index);
}
}
public boolean contains(T data) {
if (this.data.equals(data)) return true;
else {
if (this.next != null) {
return this.next.contains(data);
} else {
return false;
}
}
}
}
public LinkNode(){}
public boolean contains(T data) {
if (this.isEmpty()) return false;
else {
return this.head.contains(data);
}
}
public boolean isEmpty(){
if(count == 0 || this.head == null){
return true;
}else{
return false;
}
}
public void add(T data){
if(this.isEmpty()){
this.head=new Node(data);
}
else {
this.head.add(data);
}
this.count++;
}
public void remove(int index){
if(this.isEmpty()){
return;
}
if(index<0||this.count<=index){
return;
}
if(index==0){
Node temp=this.head;
this.head=this.head.next;
temp.next=null;
this.count--;
return;
}
else{
this.foot=0;
this.head.remove(this.head,index);
}
}
public void remove(T data){
if(this.isEmpty()){
return;
}
if(this.head.data.equals(data)){
Node temp=this.head;
this.head=this.head.next;
temp.next=null;
this.count--;
return;
}else{this.head.remove(this.head,data);}
}
public void replace(int index,T newData){
if(this.isEmpty())return;
if(index<0||this.count<=index)return;
this.foot=0;
this.head.replace(index,newData);
}
public void replace(T oldData,T newData){
if(this.isEmpty())return;
this.head.replace(oldData,newData);//交给内部类处理
}
public T get(int index){
if(this.isEmpty()){
return null;
}
this.foot=0;
return this.head.get(index);
}
public Object[] toArray(){//遍历
if(this.isEmpty()){
return null;
}
int count = this.count;
Object[] retVal = new Object[count];
for(int i=0;i<count;i++){
retVal[i] = this.get(i);
}
return retVal;
}
//@param k 步长
//@param link 需要反转的链表
public void rkNode(LinkNode link,int k){
for(int j=0;j<link.count-1;j++){//对每一个链表的元素进行判断
if((j+1)/k<(link.count/k)){//以k为步长选取每一段
if((j+1)%k!=0)//每一段首个元素不需要进行反转
link.rK((j+1)/k*k,j);
}
}
}
public void rK(int start ,int index){//对2个元素反转
if(start==0){//如果为首节点反转
Node pre=head;//pre 为目标节点的上一个节点
for(int i=0;i<=index-1;i++){
pre=pre.next;
}
Node cur=pre.next;//目标节点
Node next=cur.next;//目标节点的尾链
cur.next=head;//将目标节点定为首节点
pre.next=next;//连接尾节点
this.head=cur;//更新首节点
}
else{//非首节点反转
Node lpre=null;//开始节点的首节点
Node heads=head;
for(int i=0;i<start-1;i++){
heads=heads.next;
}//找到开始节点的上一个节点
lpre=heads;
Node starts=lpre.next;//指定开始节点即是start
Node rcur=starts;
for(int i=start;i<index;i++){
rcur=rcur.next;
}//遍历找到目标节点的上一个节点
Node rcurs=rcur.next;//获得目标节点
Node next=rcurs.next;//获得目标节点的下一个节点
rcurs.next=starts;//指定目标节点为这一段的首节点
lpre.next=rcurs;//将开始节点的上一段与开始节点连接起来
rcur.next=next;//将目标节点的下一段与目标节点连接
}
}
测试:
public static void main(String[] args){
LinkNode<Integer> mylink=new LinkNode<Integer>();
mylink.add(1);
mylink.add(2);
mylink.add(3);
mylink.add(4);
mylink.add(5);
mylink.add(6);
mylink.add(7);
mylink.add(8);
mylink.rkNode(mylink,4);
Object[] myint=mylink.toArray();
System.out.println("链表长度:"+myint.length);
for(Object in:myint){
System.out.println(in);
}
测试结果:
长度8:
k=4
k=3
参考文档:https://blog.csdn.net/zhangcongyi420/article/details/88259722