单链表
操作
基本运算
-
实现
package datastructure; import org.w3c.dom.Node; public class SLink { private int length; private Node head; private class Node { private Object data; private Node next; public Node(Object data) { this.data = data; } } // 1. 初始化InitList(L) public SLink() { this.head = null; this.length = 0; } // 2. 销毁线性表DestroyList(L) public void DestroyList() { length = 0; head = null; } // 3. 求线性表的长度GetLength(L) public int GetLength() { return length; } // 4. 求线性表中第i个元素GetElem(L,i,e) public Object GetElem(int i) { if (i < 1 || i > length) { throw new RuntimeException("i=" + i + "超出范围,i应在1~" + length + "范围内。"); } else { int n = 1; Node current = head; while (n < i) { current = current.next; n++; } return current.data; } } // 5. 按值查找Locate(L,x) public int Locate(Object x) { int i = 1; Node current = head; while (i < length) { if (current.data == x) { return i; } current = current.next; i++; } if (current.data == x) { return i; } else { return 0; } } // 6. 插入元素InsElem(L,x,i) public void InsElem(Object x, int i) { if (i < 1 || i > length + 1) { throw new RuntimeException("i=" + i + "无法插入,i应在1~" + (length + 1) + "范围。"); } else { Node newNode = new Node(x); if (head == null) { head = newNode; } else { int n = 1; Node current = head; while (current.next != null && n < i - 1) { current = current.next; n++; } if (current.next != null) { Node r = current.next; current.next = newNode; newNode.next = r; } else { current.next = newNode; } } length++; } } // 7. 删除元素DelElem(L,i) public Object DelElem(int i) { if (i < 1 || i > length) { throw new RuntimeException("i=" + i + "超出范围1~" + length); } else { Object x; int n = 1; Node current = head; Node previous = head; if (i == 1) { x = head.data; head = current.next; } else { while (n < i) { previous = current; current = current.next; n++; } x = current.data; previous.next = current.next; } length--; return x; } } // 8. 输出元素值DispList(L) public void DispList() { System.out.print("["); Node current = head; for (int i = 1; i <= length; i++) { if (i == length) { System.out.print(current.data + ""); } else { System.out.print(current.data + ","); } current = current.next; } System.out.println("]"); } }
-
测试
package datastructure; public class SLinkTest { public static void main(String[] args) { int i; Object e; SLink sLink=new SLink(); sLink.InsElem(1,1); sLink.InsElem(3,2); sLink.InsElem(1,3); sLink.InsElem(5,4); sLink.InsElem(4,5); sLink.InsElem(2,6); System.out.printf("线性表:"); sLink.DispList(); System.out.println("长度:"+sLink.GetLength()); i=3; System.out.println("第"+i+"个元素:"+sLink.GetElem(i)); e=1; System.out.println("元素"+e+"是第"+sLink.Locate(e)+"个元素"); i=4; System.out.println("删除第"+i+"个元素:"+sLink.DelElem(i)); System.out.printf("线性表:"); sLink.DispList(); } }
整体创建
//整体创建
// //1.头插法
public void CreateListF(Object[] objects) {
for (int i = 0; i < objects.length; i++) {
Node newNode = new Node(objects[i]);
newNode.next = head;
head = newNode;
length++;
}
}
//2.尾插法
public void CreateListR(Object[] objects) {
Node current = head;
for (int i = 0; i < objects.length; i++) {
Node newNode = new Node(objects[i]);
if (head == null) {
head = newNode;
current = head;
} else {
current.next = newNode;
current = current.next;
}
length++;
}
}
算法设计
1.基于单链表基本操作的算法设计
-
设计一个算法,通过一趟扫描确定单链表L(至少含两个数据结点)中第一个元素值最大的结点。
public int Maxnode() { Node current = head; Node x = current; int index = 1; for (int i = 1; i <= length; i++) { if ((int) current.data > (int) x.data) { x = current; index = i; } current = current.next; } return index; }
-
设计一个算法,通过一趟扫描确定单链表L(至少含两个数据结点)中第一个元素值最大的结点。
public int Premaxnode() { int i = Maxnode(); if (i > 1) { return i - 1; } else { return 0; } }
-
设计一个算法,删除一个单链表L(至少含两个数据结点)中第一个值最大的结点。
public void Delmaxnode() { int i = Maxnode(); DelElem(i); }
2.基于整体建表的算法设计
-
设计一个算法,将一个单链表L(至少含两个数据结点)中所有结点逆置。并分析算法的时间复杂度。
利用头插法
public static SLink Reverse(SLink sLink) { SLink newLink = new SLink(); for (int i = 1; i <= sLink.GetLength(); i++) { Object a = sLink.GetElem(i); newLink.CreateListF(new Object[]{a}); } return newLink; }
-
假设有一个单链表L,其中元素为整数且所有元素值均不相同。设计一个尽可能高效的算法将所有奇数移到所有偶数的前面。
奇数头插法,偶数尾插法。
由于之前的尾插法是从头结点开始创建,做出了修改。
public static SLink Movel(SLink sLink) { SLink newLink = new SLink(); for (int i = 1; i <= sLink.GetLength(); i++) { int a = (int) sLink.GetElem(i); if (a % 2 == 0) { newLink.CreateListR(new Object[]{a}); } else { newLink.CreateListF(new Object[]{a}); } } return newLink; }
public void CreateListR(Object[] objects) { Node current = head; if (head != null) { while (current.next != null) { current = current.next; } } for (int i = 0; i < objects.length; i++) { Node newNode = new Node(objects[i]); if (head == null) { head = newNode; current = head; } else { current.next = newNode; current = current.next; } length++; } }
3.有序单链表的二路归并算法
-
设ha和hb分别是两个带头结点的递增有序单链表。设计一个算法,将这两个有序链表的所有数据结点合并成一个递增有序的单链表hc,并分析算法的时间和空间复杂度。要求hc单链表仍使用原来两个链表的存储空间,不另外占用其他的存储空间,ha和hb两个表中允许有重复的数据结点。
public static SLink Merge(SLink A, SLink B) { SLink C = new SLink(); C = A; Node curB = B.head; Node current = C.head; int i = 1; while (current != null && curB != null) { int a = (int) current.data; int b = (int) curB.data; if (a < b) { current = current.next; i++; } else { C.InsElem(curB.data, i); curB = curB.next; i++; } } if (curB != null) { C.CreateListR(new Object[]{curB.data}); curB = curB.next; } return C; }
-
设ha和hb分别是两个带头结点的递增有序单链表。设计一个算法,由表ha和表hb的所有公共结点(两单链表中data值相同的结点)产生一个递增有序单链表hc,分析算法的时间和空间复杂度。要求不破坏原来两个链表ha和hb的存储空间。
public static SLink Commelent(SLink A, SLink B) { SLink C = new SLink(); Node curA = A.head; Node curB = B.head; while (curA != null && curB != null) { int a = (int) curA.data; int b = (int) curB.data; if (a == b) { C.CreateListR(new Object[]{a}); curA = curA.next; curB = curB.next; } else { if (a < b) { curA = curA.next; } else { curB = curB.next; } } } return C; }
4.单链表的排序算法
设计一个完整的程序,根据用户输入的学生人数n(n≥3)及每个学生姓名和成绩建立一个单链表,并按学生成绩递减排序,然后按名次输出所有学生的姓名和成绩。
- 设计存储结构
- 设计基本运算方法
- void CreateStudent(StudList∗&sl):采用交互式方式创建学生单链表。
- void DestroyList(StudList∗&L):销毁学生单链表。
- void DispList(StudList∗L):输出学生单链表。
- void SortList(StudList∗&L):将学生单链表按成绩递减排序。
- 设计主函数
package datastructure.student;
import java.util.Scanner;
public class Student {
private int length;
private Node head;
private Node rear;
private class Node {
private String name;
private int score;
private Node next;
public Node(String name, int score) {
this.name = name;
this.score = score;
}
}
public Student() {
this.head = null;
this.length = 0;
this.rear = head;
}
// 1. void CreateStudent(StudList∗&sl):采用交互式方式创建学生单链表。
public void CreateStudent(String name, int score) {
Node newNode = new Node(name, score);
if (head == null) {
head = newNode;
rear = head;
} else {
rear.next = newNode;
rear = newNode;
}
length++;
}
// 2. void DestroyList(StudList∗&L):销毁学生单链表。
public void DestroyList() {
length = 0;
head = null;
rear = head;
}
// 3. void DispList(StudList∗L):输出学生单链表。
public void DispList() {
Node current = head;
System.out.printf("[");
for (int i = 1; i <= length; i++) {
if (i != length) {
System.out.printf(current.name + ":" + current.score + ",");
} else {
System.out.printf(current.name + ":" + current.score + "");
}
current = current.next;
}
System.out.println("]");
}
// 4. void SortList(StudList∗&L):将学生单链表按成绩递减排序。
public void InsElem(int i, Node node) {
if (head == null) {
head = node;
} else {
int n = 1;
Node current = head;
Node previous = head;
if (i == 1) {
node.next = head;
head = node;
} else {
while (n < i) {
previous = current;
current = current.next;
n++;
}
previous.next = node;
node.next = current;
}
}
length++;
}
public void SortList() {
Student newList = new Student();
Node cur = head;
for (int i = 1; i <= length; i++) {
int j = 1;
Node current = newList.head;
while (j <= newList.length && cur.score < current.score) {
current = current.next;
j++;
}
Node node = new Node(cur.name, cur.score);
newList.InsElem(j, node);
cur = cur.next;
}
this.head = newList.head;
this.length = newList.length;
this.rear = newList.rear;
}
}