顺序表的实现
顺序表的建立及内部方法:
package liner;
import java.util.Iterator;
public class SequentList<T> implements Iterable<T>{
//存储元素的数组
private T[] eles;
//记录当前顺序表中元素的个数
private int N;
//构造方法
public SequentList(int capacity){
//初始化数组
this.eles = (T[])new Object[capacity];
//初始化长度
this.N = 0;
}
//将一个线性表设置为空表
public void clear(){
this.N = 0;
}
//判断当前线性表是否为空表
public boolean isEmpty(){
return N == 0;
}
//获取线性表的长度
public int length(){
return N;
}
//获取指定位置的元素
public T get(int i){
return eles[i];
}
//向线性表中添加元素t
public void insert(T t){
eles[N++] = t;
}
//向线性表中插入元素
public void insert(int i,T t){
//先把i和后面的元素让位
N++;
for (int j = N; j > i; j--){
eles[j] = eles[j - 1];
}
//放入t
eles[i] = t;
}
//删除指定位置i处的元素,并返回该元素
public T remove(int i){
//记录索引i处的值
T current = eles[i];
//将后面的元素依次往前移动一位
for (int index = i; index < N - 1; index++){
eles[index] = eles[index + 1];
}
N --;
return current;
}
//查找t元素第一次出现的位置
public int indexOf(T t){
for (int i = 0; i <= N - 1; i++) {
if (eles[i].equals(t)){
return i;
}
}
return -1;
}
@Override
public Iterator<T> iterator() {
//由于是接口无法直接创建对象,因此使用内部类实现该接口
return new SIterator();
}
private class SIterator implements Iterator{
//使用一个私有变量作为指针去遍历数组
private int crsor;
//使用构造方法将指针初始化为0
public SIterator(){
this.crsor=0;
}
@Override
public boolean hasNext() {
return crsor < N;
}
@Override
public Object next() {
return eles[crsor++];
}
}
}
链表
类名 | Node |
---|---|
构造方法 | Node(T t, Node next):创建Node对象 |
成员变量 | T item: 存储数据 ; Node next:指向下一个结点 |
单链表
package liner;
import java.util.Iterator;
/*
构造方法:LinkList():创建linklist对象
成员方法:
1.public void clear():置空线性表
2.public boolean isEmpty()判断链表是否为空,是则返回true
3.public int length():获取线性表中元素的个数
4.public T get(int i)读取并返回线性表中第i个元素的值
5.public void insert(T t):往线性表中添加一个元素
6.public void insert(T t, int i)往线性表中的第i个元素之间的位置插入一个值为t的元素
7.public T remove(int i):删除并返回线性表中第i个元素的值
8.public int indexOf(T t):返回线性表中首次出现的值为t的元素的索引
成员内部类:
private class Node<T>: 节点类
成员变量:
1.private Node head: 记录首节点
2.private int N: 记录链表的长度
*/
public class LinkList<T> implements Iterable<T>{
private Node head;
private int N;
private class Node{
//定义数据域
T item;
//下一个结点
Node next;
public Node(T item, Node next){
this.item = item;
this.next = next;
}
}
public LinkList(){
//初始化头结点
this.head = new Node(null, null);
//初始化元素个数
this.N = 0;
}
//清空链表
public void clear(){
//头结点指向空
head.next = null;
//元素个数为0
N = 0;
}
//获取链表的长度
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N == 0 && head.next == null;
}
//获取指定位置i处的元素
public T get(int i){
//通过循环,从头结点开始往后找,依次找i次,就可以找到对应的元素
Node n = head.next;
for (int index = 0; index < i; index++){
n = n.next;
}
return n.item;
}
//向链表中添加元素t
public void insert(T t){
//找到当前最后一个节点
Node n = head;
while (n.next != null){
n = n.next;
}
//创建新节点,保存元素t
Node newNode = new Node(t, null);
//让当前最后一个结点指向新节点
n.next = newNode;
//节点元素个数++
N++;
}
//向链表中指定位置i插入元素t
public void insert(int i, T t){
// Node n = head.next;
// Node newNode = new Node(t, null);
// if (i == 0){
// head.next = newNode;
// newNode.next = n.next;
// }
// //找到i位置的前面一个节点
// for (int index = 0; index < i - 1; index++ ){
// n = n.next;
// }
// newNode.next = n.next;
// n.next = newNode;
//找到i位置的前一个结点
Node pre = head;
for (int index = 0; index <= i - 1; index++){
pre = pre.next;
}
//找到i位置的结点
Node cur = pre.next;
Node newNode = new Node(t, cur);
pre.next = newNode;
N++;
}
//删除指定位置i处的元素,并返回被删除的元素
public T remove(int i){
Node pre = head;
//找到i-1位置处的结点
for (int index = 0; index <= i -1; index++){
pre = pre.next;
}
Node curr = pre.next;
pre.next = curr.next;
N--;
return curr.item;
}
//查找元素t在链表中第一次出现的位置
public int indexOf(T t){
//从头结点开始,依次找到每一个节点,取出item和t比较,如果相同,则找到了
Node n = head.next;
for (int index = 0; index < N; index ++){
if (n.item == t) return index;
else n = n.next;
}
return -1;
}
@Override
public Iterator iterator() {
//由于接口无法创建对象,因此使用内部类
return new SIterator();
}
private class SIterator implements Iterator{
//使用一个私有变量作为指针去遍历数
private Node cursor;
//使用构造方法将指针初始化为0
public SIterator(){
//指针初始值为0
this.cursor = head;
}
@Override
public boolean hasNext() {
//指针小于N-1则成立
return cursor.next != null;
}
@Override
public Object next() {
cursor = cursor.next;
return cursor.item;
}
}
}
双向链表
类名 | Node |
---|---|
构造方法 | Node(T t, Node pre, Node next):创建Node对象 |
成员变量 | T item;存储数据 Node next;指向下一个结点 Node pre 指向上一个结点 |
package Test;
import liner.LinkList;
import liner.TwoWayLinkList;
public class TwoWayLinkListTest {
public static void main(String[] args) {
TwoWayLinkList<String> lst = new TwoWayLinkList<>();
lst.insert("张三");
lst.insert("李四");
lst.insert("王五");
lst.insert(1, "赵六");
// for (int i = 0; i < lst.length(); i++){
// System.out.println(lst.get(i));
// }
for (String s : lst) {
System.out.println(s);
}
String removeResult = lst.remove(1);
System.out.println("被移除的元素为:" + removeResult);
System.out.println("第一个元素是:" + lst.getFirst());
System.out.println("最后一个元素是:" + lst.getLast());
lst.clear();
System.out.println("被清空后的链表的元素个数为:" + lst.length());
}
}
链表的反转
public void reserve():对整个链表进行反转
public Node reverse(Node curr): 反转链表中的某个结点curr,并把反转后的curr结点返回。
使用递归可以完成反转,递归反转其实就是从原链表的第一个存数据的结点开始,依次调用反转的每一个结点,知道最后一个结点反转完毕,整个链表就反转完毕。
//用来反转整个链表
public void reverse(){
//判断当前链表是否为空,如果是,则结束运行,不是则调用重载的reverse方法
if (isEmpty()){
return;
}
reverse(head.next);
}
//用来反转单个结点,这里的pre指的是反转后的pre
public Node reverse(Node curr){
if (curr.next == null){
head.next = curr;
return curr;
}
//递归的反转当前结点的下一节点,返回值就是链表反转后,当前结点的上一个结点
Node pre = reverse(curr.next);
//让返回结点的下一个结点变成当前结点curr
pre.next = curr;
//把当前结点的下一个结点变为空
curr.next = null;
return curr;
}
快慢指针
快慢指针指的是定义两个指针,这两个指针移动速度一快一慢,一次来制造出自己想要的差值,这个差值可以使我们找到链表相应的结点。一般情况下,快指针的移动步长为满指针的两倍。
1.使用快慢指针得到链表的中间值
public class FastSlowTest {
public static void main(String[] args) {
Node<String> seven = new Node<>("gg", null);
// Node<String> six= new Node<>("ff", seven);
Node<String> five = new Node<>("ee", null);
Node<String> four = new Node<>("dd", five);
Node<String> three = new Node<>("cc", four);
Node<String> second = new Node<>("bb", three);
Node<String> first = new Node<>("aa", second);
//查找中间值
String mid = getMid(first);
System.out.println("中间值为:" + mid);
}
//first为链表的首节点,返回值为链表的中间结点的值
public static String getMid(Node<String> first){
//定义两个指针
Node fast = first;
Node slow = first;
//使用两个指针遍历链表,当快指针没有下一个结点时,就可以结束,此时慢指针指向的结点为中间值
while (fast.next != null && fast != null){
fast = fast.next.next;
slow = slow.next;
}
return String.valueOf(slow.item);
}
//定义结点类
private static class Node<T>{
//存储数据
T item;
//下一个结点
Node next;
public Node(T item, Node next){
this.item = item;
this.next = next;
}
}
}
2.使用快慢指针解决是否有环以及环的入口
当快慢指针相遇时,我们可以确定链表中有环,这是重新设定一个新指针指向链表的起点,且步长与慢指针一样为1,则慢指针与新指针相遇的地方就是环的入口。
public class CircleListCheckTest {
public static void main(String[] args) {
Node<String> seven = new Node<>("gg", null);
Node<String> six= new Node<>("ff", seven);
Node<String> five = new Node<>("ee", six);
Node<String> four = new Node<>("dd", five);
Node<String> three = new Node<>("cc", four);
Node<String> second = new Node<>("bb", three);
Node<String> first = new Node<>("aa", second);
//产生环
seven.next = three;
//判断是否有环
boolean circle = isCircle(first);
if (circle){
System.out.println("有环");
//查找有环链表的入口
Node entrance = getEntrance(first);
System.out.println("环的入口元素为:" + entrance.item);
}
else System.out.println("没有环");
}
//查找有环链表的入口结点
public static Node getEntrance(Node<String> first){
Node fast = first;
Node slow = first;
Node newNode = first;
while (fast.next != null && fast != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
break;
}
}
while (newNode != slow){
newNode = newNode.next;
slow = slow.next;
}
return newNode;
}
//first为链表的首节点,返回值为链表的中间结点的值
public static boolean isCircle(Node<String> first){
//定义两个指针
Node fast = first;
Node slow = first;
//使用两个指针遍历链表,当快指针没有下一个结点时,就可以结束,此时慢指针指向的结点为中间值
while (fast.next != null && fast != null){
fast = fast.next.next;
slow = slow.next;
if (fast == slow){
return true;
}
}
return false;
}
//定义结点类
private static class Node<T>{
//存储数据
T item;
//下一个结点
Node next;
public Node(T item, Node next){
this.item = item;
this.next = next;
}
}
}