(此文章源代码及更多数据结构的代码都在git)
链表作为最基本的数据结构,在程序设计中有着非常重要的作用,其存储特点如下:可以用任意一组存储单元来存储单链表中的数据元素(存储单元可以是不连续的),而且,除了存储每个元素的值以外,海必须存储指示其后继元素的信息。这两部分信息组成的数据元素的存储映像称为结点(Node)。N个结点链在一起被称为链表,当结点值包含其后继结点的信息的链表就被称为单链表。
存储格式:链式
特点:存储单元可以不连续
存取方式:顺序存取
1.定义结点类
//链表结点
class Node{
Node next = null;
int data;
public Node(int data){
this.data = data;
}
}
2.链表的基本操作
public class MyLinkedList {
Node head = null; //链表的头指针
/**向链表中插入数据
* @param d:插入数据的内容
* */
public void addNode(int d){
Node newNode = new Node(d);
if(head == null){ //空链表,插入为头指针
head = newNode;
}else{
Node p = head;
while(p.next != null){
p = p.next;
}
p.next = newNode;
}
}
/**
* @param index:删除第index个节点
* @return 成功返回true,失败返回false
* */
public boolean delNode(int index){
if(index < 1 || index > length()){
return false;
}
//删除链表第一个节点
if(index == 1){
head = head.next;
return true;
}else{
//不是第一个节点
int i = 1;
Node preNode = head;
Node curNode = preNode.next;
while(curNode != null){
if(i == index){
preNode.next = curNode.next;
return true;
}
preNode = curNode;
curNode = curNode.next;
i++;
}
}
return true;
}
/**
* @return 返回节点的长度
*/
public int length(){
int length = 0;
Node p = head;
while(p != null){
length++;
p = p.next;
}
return length;
}
public int length(Node head){
int length = 0;
Node p = head;
while(p != null){
length++;
p = p.next;
}
return length;
}
/**
* 输出链表
*/
public void printList(){
Node p = head;
while(p != null){
System.out.println(p.data);
p = p.next;
}
}
}
3.对链表进行排序
返回排序后的头结点(代码为选择排序)
/**
* 对链表进行排序
* 方法为选择排序
* @return 返回排序后的头节点
*/
public Node orderList(){
Node nextNode = null;
int temp = 0;
Node curNode = head;
while(curNode.next != null){
nextNode = curNode.next;
while(nextNode != null){
if(nextNode.data < curNode.data){
swap(curNode,nextNode);
}
nextNode = nextNode.next;
}
curNode = curNode.next;
}
return head;
}
/**
* 交换两个节点的值
*/
private static void swap(Node i,Node j){
int temp = i.data;
i.data = j.data;
j.data = temp;
}
4.从链表中删除重复数据
1)遍历链表,把值存储到一个Hashtable中,在遍历过程中,若当前访问的值在Hashtable中已经存在,则说明这个数据是重复的,因此就可以删除。(省时间)
/**
* 从链表中删除重复数据
* @param head
*/
public static void deletDuplecate(Node head){
Hashtable<Integer,Integer> hm = new Hashtable<Integer,Integer>();
Node p = head;
Node pre = null;
while(p != null){
if(hm.containsKey(p.data)){
pre.next = p.next;
}else{
hm.put(p.data,1);
pre = p;
}
p = p.next;
}
}
/**
* 从链表中删除重复数据
* 省空间,费时间
* @param head
*/
public static void deletDuplecate1(Node head){
Node p = head;
Node q;
while(p != null){
q = p;
while(q.next != null){
if(q.next.data == p.data){
q.next = q.next.next;
}else{
q = q.next;
}
}
p = p.next;
}
}
5.找出单链表中倒数第k个元素
首先的想法为两次遍历链表,第一次求出链表的长度n,第二次找出n-k个元素。方法可优化为:设置两个指针,其中一个指针比另一个指针先前移k-1步(虽然Java中没有指针的概念,但是引用与指针有着非常相似的性质。),然后两个指针同时往前移动。循环直到先行的指针值为null时,另一个指针所指的位置就是所要找的位置。
/**
* 找出链表中的倒数第k个元素
* @param head
*/
public static Node findElem(Node head,int k){
MyLinkedList m = new MyLinkedList();
if(k < 1 || k > m.length()){
return null;
}
Node p1 = head;
Node p2 = head;
for(int i = 0; i < k; i++){
p1 = p1.next;
}
while(p1 != null){
p1 = p1.next;
p2 = p2.next;
}
return p2;
}
6.从尾到头输出单链表
/**
* 从尾到头输出单链表
* 递归输出
*/
public void printListReversely(Node head){
if(head != null){
printListReversely(head.next);
System.out.println(head.data);
}
}
7.寻找单链表的中间结点
为了节省时间、避免两次遍历,可设置两个指针,快指针一次前移两步,慢指针一次前移一步,故当快指针到达链表尾部时,慢指针到达链表的中间结点。
/**
* 寻找链表的中间节点
*/
public Node SearchMid(Node head){
Node p = head;
Node q = head;
while(p != null && p.next != null && p.next.next != null){
p = p.next.next;
q = q.next;
}
return q;
}
8.实现链表的反转
需注意一旦调整了指针的指向,链表就断开了,因为已经没有指针指向该结点了,故在调整指针前需要先把该结点保存下来。 /**
* 实现链表的反转
*/
public void Reverse(Node head){
Node Rhead = head; //反转后的链表
Node p = head;
Node pPrev = null;
while(p != null){
Node pNext = p.next; //保存下一个节点
if(pNext == null){
Rhead = p;
}
p.next = pPrev;
pPrev = p;
p = pNext;
}
head = Rhead;
}
9.在不知道头指针的情况下删除指定结点
1)若待删除的结点为链表尾结点,则无法删除,因为删除后无法使其前驱结点的next指针置为空;
2)若待删除的结点不是尾结点,则可以通过交换这个结点与其后继结点的值,然后删除后继结点。
/**
* 在不知道头指针的情况下删除指定节点
*/
public boolean deleteNode(Node n){
if(n == null || n.next == null){
return false;
}else{
int temp = n.data;
n.data = n.next.data;
n.next.data = temp;
n.next = n.next.next;
return true;
}
}
参考文献:
《Java程序员面试笔试宝典》