链表作为最基本的数据结构,在程序设计中有着很重要的作用。存储特点如下:可以用任意一个存储单元来存储单链表中的数据元素,还必须存储指示其直接后继元素的信息。这两部分组成的数据元素称为一个结点,N个结点链在一块称为链表,当结点只包含其后继结点信息的链表称为单向链表。同理当结点既包含其后继结点信息又包含其上一个结点信息的链表称为双向链表。
下面为一些操作单向链表的方法实现:
package test;
/**
* 定义结点类
*/
public class Node
{
private int data;//结点数据
private Node next;//下一个结点
public Node(int data)
{
this.data = data;
}
public int getData()
{
return data;
}
public void setData(int data)
{
this.data = data;
}
public Node getNext()
{
return next;
}
public void setNext(Node next)
{
this.next = next;
}
}
package test;
import java.util.HashMap;
import java.util.Map;
public class NodeDemo
{
public static void main(String[] args)
{
Node head = new Node(2);
Node node1 = new Node(1);
Node node2 = new Node(0);
Node node3 = new Node(2);
Node node4 = new Node(1);
Node node5 = new Node(1);
head.setNext(node1);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(node4);
node4.setNext(node5);
printList(head);//正序打印链表
Node n = reverse(head);//反转链表
printList(n);
//以下还有很多操作单链表的方法
}
//正序打印链表
public static void printList(Node head)
{
while(head!=null)
{
System.out.print(head.getData()+" ");
head = head.getNext();
}
System.out.println();
}
//反序打印链表
public static void printListReverse(Node head)
{
if(head != null)
{
printListReverse(head.getNext());
System.out.print(head.getData()+" ");
}
}
//递归实现单向链表反转,返回倒序链表
public static Node reverse(Node head)
{
if(head==null || head.getNext()==null)
{
return head;
}
Node rehead = reverse(head.getNext());
head.getNext().setNext(head);
head.setNext(null);
return rehead;
}
//非递归实现单向链表反转,采用交换指针的方式,返回倒序链表
public static Node reverse2(Node head)
{
if(head==null || head.getNext()==null)
{
return head;
}
Node pre = head;//当前结点
Node next = pre.getNext();//下一个结点
Node temp = null;//临时结点
while(next!=null)
{
temp = next.getNext();//遍历到最后temp为null
next.setNext(pre);
pre = next;
next = temp;
}
head.setNext(null);
return pre;
}
/**
* 判断链表是否有环
*
* @param head
* @return
*/
public static boolean hasLoop(Node head) {
if (head == null || head.getNext() == null)
return false; //若链表仅存在头节点,不认为是环
boolean flag = false;
Node pFast = head;
Node pSlow = head;
while (pFast.getNext() != null && pFast.getNext().getNext() != null) {
pFast = pFast.getNext().getNext();
pSlow = pSlow.getNext();
if (pFast == pSlow) {
flag = true;
break;
}
}
return flag;
}
//向head链表尾部中插入数据为data的结点
public static Node addNodeEnd(Node head,int data)
{
Node node = new Node(data);
if(head==null)
{
return node;
}
Node temp = head;
while(temp.getNext()!=null)
{
temp = temp.getNext();
}
temp.setNext(node);
return head;
}
//向head链表第i个结点后插入数据为data的结点
public static Node addNode(Node head,int i,int data)
{
Node node = new Node(data);
if(head==null)
{
return node;
}
Node temp = head;
int count = 0;
while(temp.getNext()!=null)
{
if(count == i)
{
Node n = temp.getNext();
temp.setNext(node);
node.setNext(n);
}
temp = temp.getNext();
count++;
}
return head;
}
//返回指定链表的结点个数
public static int getLength(Node head)
{
int count = 0;
Node temp = head;
while(temp!=null)
{
temp = temp.getNext();
count++;
}
return count;
}
//删除第i个结点
public static Node deleteNode(Node head,int i)
{
if(i<1 || i>getLength(head))
{
System.out.println("结点位置不合理");
return head;
}
if(i==1)
{
head = head.getNext();
return head;
}
Node temp = head;
int count = 2;
while(temp!=null)
{
if(count==i)
{
temp.setNext(temp.getNext().getNext());
return head;
}
temp = temp.getNext();
count++;
}
return head;
}
//删除数据重复的结点,使用HashMap,需要额外的内存空间
public static Node deleteSameNode(Node head)
{
if(head==null || head.getNext()==null)
{
return head;
}
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Node pre = head;
Node temp = null;
while(pre!=null)
{
if(map.containsKey(pre.getData()))
{
temp.setNext(pre.getNext());
}
else
{
map.put(pre.getData(), 1);
}
temp = pre;
pre = pre.getNext();
}
return head;
}
//删除数据重复结点,使用双重循环方式,时间复杂度高,不需要额外内存空间
public static Node deleteSameNode2(Node head)
{
if(head==null || head.getNext()==null)
{
return head;
}
Node pre = head;
while(pre!=null)
{
Node temp = pre;
while(temp.getNext()!=null)
{
if(pre.getData()==temp.getNext().getData())
{
temp.setNext(temp.getNext().getNext());
}
else
{
temp = temp.getNext();
}
}
pre = pre.getNext();
}
return head;
}
//链表排序,结点数据从小到大排序
public static Node sort(Node head)
{
if(head==null || head.getNext()==null)
{
return head;
}
Node temp = null;
Node pre = head;
while(pre.getNext()!=null)
{
temp = pre.getNext();
while(temp!=null)
{
if(pre.getData()>temp.getData())
{
int i = pre.getData();
int j = temp.getData();
pre.setData(j);
temp.setData(i);
}
temp = temp.getNext();
}
pre = pre.getNext();
}
return head;
}
/**
*找出倒数第k个结点元素。
*时间复杂度比(先遍历链表得到长度,再遍历到length-k个结点)更高效点。
*思路:先让p1前移k-1个位置,然后两个指针同时前移,
*直到先行的指针值为空,另一个指针就是所找的位置。
*
* @param head 链表头结点
* @param k 倒数第k个结点
* @return 倒数第k个结点的数据
*/
public static int findNode(Node head,int k)
{
if(k<1 || k>getLength(head))
{
return -1;
}
Node p1 = head;
Node p2 = head;
for(int i=0;i<k-1;i++)
{
p1 = p1.getNext();
}
while(p1!=null)
{
p1 = p1.getNext();
p2 = p2.getNext();
}
return p2.getData();
}
}