顺序表在内存中是数组的形式存储
类名 | SequenceList |
---|---|
构造方法 | SequenceList(int capacity):创建容量为capacity的SequenceList对象 |
成员方法 | 1. public void clear():空置线性表 2. public boolean isEmpty():判断线性表是否为空,是返回true,否返回false 3. public int length():获取线性表中元素的个数 4. public T get(int i):读取并返回线性表中的第i个元素的值 5. public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素 6. public void insert(T t):向线性表中添加一个元素t 7. public T remove(int i):删除并返回线性表中第i个数据元素。 8. public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则返回-1。 |
成员变量 | 1. private T[] eles:存储元素的数组 2.private int N:当前线性表的长度 |
//用来构造顺序表
public class SequenceList<T> implements Iterable{
//存储元素的数组
private T[] eles;
//当前线性表的长度
private int N;
//获得当前容量
private int capacity;
//构造方法
public SequenceList(int capacity) {
//强制类型转化
this.eles = (T[])new Object[capacity];
//初始化长度
N = 0;
//获取当前顺序表的容量
this.capacity = capacity;
}
//空置线性表
public void clear() {
for (int index = 0 ; index<getLength();index++){
eles[index] = null;
}
this.N = 0;
}
//判断线性表是否为空,是返回true,否返回false
public boolean isEmpty() {
return N==0;
}
//获取线性表中元素的个数
public int getLength() {
return N;
}
//获取线性表的容量
public int getCapacity() {
return capacity;
}
//读取并返回线性表中的第i个元素的值
public T get(int i) {
if (i <= 0 || i>=N){
throw new RuntimeException("当前元素不存在");
}
return eles[i];
}
//在线性表的第i个元素之前插入一个值为t的数据元素
public void insert(int i,T t) {
//如果当前元素的数量等于当前数组的长度
if(N==eles.length){
//扩容
resize(2*eles.length);
}
//将i索引处以及后面的元素全部向后移动
for (int index = N;index>i;index--){
eles[index] = eles[index-1];
}
eles[i] = t;
N++;
}
//向线性表中添加一个元素t
public void insert(T t) {
//如果当前元素的数量等于当前数组的长度
if(N==eles.length){
//扩容
resize(2*eles.length);
}
//先将N处赋值为t,随后N自增
eles[N]=t;
N++;
}
//删除并返回线性表中第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--;
//如果当前元素的数量等于当前(数组的长度/4)
if(N<eles.length/4){
//将顺序表的长度变为原来的一半
resize(eles.length/2);
}
return current;
}
//根据参数的newSize,重新来设置数组的大小
public void resize(int newSize){
//定义一个临时数组,指向原数组,用来提供复制数组
T[] temp = eles;
//容量翻倍
eles = (T[]) new Object[newSize];
//把原数组的数据拷贝到新数组即可
for (int i = 0 ; i<N;i++){
eles[i] = temp[i];
}
//重新定义容量的大小
capacity = newSize ;
}
//返回线性表中首次出现的指定的数据元素的位序号,若不存在,则返 回-1。
public int indexOf(T t){
if(t==null){
throw new RuntimeException("查找的元素不合法");
}
for (int i = 0; i < N; i++) {
if (eles[i].equals(t)){
return i;
}
}
return -1;
}
//实现遍历输出
@Override
public Iterator iterator() {
return new SIterator();
}
private class SIterator implements Iterator{
private int index;
public SIterator(){
this.index = 0;
}
@Override
public boolean hasNext() {
//表示还有下一个元素
return index<N;
}
@Override
public Object next() {
return eles[index++];
}
}
}
O(1)
;O(n)
;链表分为两个类组成,分别为Node
节点类和LinkList
链表类
类名 | Node |
---|---|
构造方法 | Node(T t,Node next):创建Node对象 |
成员变量 | T item:存储数据 Node next:指向下一个结点 |
//用来定义节点
public class Node<T> {
//存储数据
T item;
//下一个节点
Node next;
public Node(T item, Node next) {
this.item = item;
this.next = next;
}
}
类名 | LinkList |
---|---|
构造方法 | LinkList():创建LinkList对象 |
成员方法 | 1. public void clear():空置线性表 2. public boolean isEmpty():判断线性表是否为空,是返回true,否返回false 3. public int length():获取线性表中元素的个数 4. public T get(int i):读取并返回线性表中的第i个元素的值 5. public void insert(T t):往线性表中添加一个元素; 6. public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素。 7. public T remove(int i):删除并返回线性表中第i个数据元素。 8. public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则 返回-1。 |
成员内容类 | private class Node:结点类 |
成员变量 | 1. private Node head:记录首结点 2.private int N:记录链表的长度 |
//实现链表的构造
public class LinkList<T> implements Iterable{
//记录头节点
private Node<T> head;
//记录链表的长度
private int N;
//构造方法
public LinkList(){
//初始化头节点
this.head = new Node<T>(null,null);
//初始化元素个数
this.N = 0;
}
//清空链表:原理是断开头节点的指向,并且将链表置零
public void clear(){
head.next = null;
}
//获取链表的长度
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N==0;
}
//获取指定位置i处的元素
public T get(int i){
Node n = head.next;
for (int index = 0 ; index<i ; index++){
n = n.next;
}
return (T) n.item;
}
//向链表中插入元素
public void insert(T t){
//找到当前的最后一个节点
Node n = head;
while (n.next!=null){
n = n.next;
}
//创建节点,保存元素
Node newNode = new Node(t,null);
//让当前最后一个节点指向新节点
n.next = newNode;
//元素的个数++
N++;
}
//向链表的指定位置插入元素
public void insert(int i , T t){
if (i<0 || i>=N){
throw new RuntimeException("位置不合法");
}
//找到i-1和i节点
Node preNode = head;// i-1 节点
for (int index = 0 ; index<=i-1 ; index++){
preNode = preNode.next;
}
Node currentNode = preNode.next;// i 节点
//创建新节点newNode
Node newNode = new Node(t,null);
//让i-1节点的next节点指向创建的newNode
preNode.next = newNode;
//将newNode的next节点指向原本的i节点
newNode.next = currentNode;
//元素个数++
N++;
}
//删除指定位置的索引,并且返回被删除的元素
public T remove(int i){
if (i<0 || i>=N){
throw new RuntimeException("位置不合法");
}
//找到 i-1 、 i 、i+1 节点
Node preNode = head ; //找到i-1
for (int index = 0 ; index<=i-1 ; index++){
preNode = preNode.next;
}
Node currentNode = preNode.next; //找到i
Node nextNode = currentNode.next; //找到i+1
//将i-1的next节点指向i+1即可
preNode.next = nextNode ;
//元素个数--
N--;
return (T) currentNode.item;
}
//查找元素t在链表中第一次出现的位置
public int indexOf(T t){
Node n = head ;
//依次去除节点元素进行比较
for (int i = 0;n.next!=null;i++){
n = n.next;
if (t.equals(n.item)){
return i;
}
}
return -1;
}
//实现遍历输出
@Override
public Iterator iterator() {
return new LIterator();
}
public class LIterator implements Iterator{
private Node n;
public LIterator(){
this.n = head;
}
@Override
public boolean hasNext() {
return n.next!=null;
}
//获取下一个元素的值
@Override
public Object next() {
n = n.next;
return n.item;
}
}
}
类名 | Node |
---|---|
构造方法 | Node(T t,Node next):创建Node对象 |
成员变量 | T item:存储数据 Node next:指向下一个结点 Node pre:指向上一个结点 |
public class Node<T> {
//下一个节点
public Node next;
//上一个节点
public Node pre;
//存储数据
public T item;
//构造函数
public Node(Node pre, Node next, T item) {
this.pre = pre;
this.next = next;
this.item = item;
}
}
类名 | DoublyLinkList |
---|---|
构造方法 | DoublyLinkList():创建DoublyLinkList对象 |
成员方法 | 1. public void clear():空置线性表 2. public boolean isEmpty():判断线性表是否为空,是返回true,否返回false 3. public int length():获取线性表中元素的个数 4. public T get(int i):读取并返回线性表中的第i个元素的值 5. public void insert(T t):往线性表中添加一个元素; 6. public void insert(int i,T t):在线性表的第i个元素之前插入一个值为t的数据元素。 7. public T remove(int i):删除并返回线性表中第i个数据元素。 8. public int indexOf(T t):返回线性表中首次出现的指定的数据元素的位序号,若不存在,则返回-1。 9. public T getFirst():获取第一个元素 10. public T getLast():获取最后一个元素 |
成员内容类 | private class Node:结点类 |
成员变量 | 1. private Node head:记录首结点 2. private Node end:记录尾结点 3.private int N:记录链表的长度 |
public class DoublyLinkList<T> implements Iterable{
//记录头节点
private Node<T> head;
//记录尾节点
private Node<T> end;
//记录链表的长度
private int N;
//构造方法
public DoublyLinkList(){
//初始化头节点和尾节点
this.head = new Node<T>(null,null,null);
this.end = null;
//所以这个地方头节点和尾节点不占用长度
this.N = 0;
}
//清空链表:原理是断开头节点和尾节点的指向,并且将链表置零
public void clear(){
head.next = null;
end = null;
N = 0;
}
//获取链表的长度
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N==0;
}
//获取第一个元素
public T getHead(){
if (isEmpty()){
return null;
}
return (T) head.next.item;
}
//获取最后一个元素
public T getLast(){
if (isEmpty()){
return null;
}
return (T) end.item;
}
//向链表中插入元素(默认是尾部)
public void insert(T t){
//1. 如果链表为空
if (isEmpty()){
//1.1 创建新的节点
Node newNode = new Node(head, null, t);
//1.2 让新的的节点称之为尾节点
end = newNode;
//1.3 让头节点指向尾节点
head.next = end;
}else {
//2. 如果链表不为空
Node oldNode = end;
//2.1 创建新的节点
Node newNode = new Node(oldNode,null,t);
//2.2 让当前的尾节点指向新节点
oldNode.next = newNode;
//2.3 让新节点成为尾节点
end = newNode;
}
N++;
}
//向链表的指定位置插入元素
public void insert(int i , T t){
if (i<0 || i>=N){
throw new RuntimeException("位置不合法");
}
//找到 i-1 的节点
//假如在 3 位置插入新节点,我们就是遍历从0-2,恰好可以找到2节点
Node preNode = head;
for (int index = 0 ; index<=i-1 ; index++){
preNode = preNode.next;
}
//找到 i 位置节点
Node currentNode = preNode.next;
//创建新节点
Node newNode = new Node(null,null,t);
//修改指向
preNode.next = newNode;
newNode.next = currentNode;
currentNode.pre = newNode;
newNode.pre = preNode;
//元素个数加一
N++;
}
//删除指定位置的索引,并且返回被删除的元素
public T remove(int i){
if (i<0 || i>=N){
throw new RuntimeException("位置不合法");
}
//找到i位置的节点
Node node = head;
for (int index = 0 ;index<=i ; index++){
node = node.next;
}
//找到 i+1 位置节点
Node nextNode = node.next;
//找到 i-1 位置节点
Node preNode = node.pre;
//修改指向
preNode.next = nextNode;
nextNode.pre = preNode;
N--;
return (T) node.item;
}
//获取指定位置i处的元素
public T get(int i){
Node node = head;
for (int index = 0 ; index<=i ; index++){
node = node.next;
}
return (T) node.item;
}
//查找元素t在链表中第一次出现的位置
public int indexOf(T t){
Node node = head;
for (int index = 0 ; node.next != null ; index++){
node = node.next;
if (t.equals(node.item)){
return index;
}
}
return -1;
}
@Override
public Iterator iterator() {
return new DIterator();
}
private class DIterator implements Iterator{
private Node n;
public DIterator() {
this.n = head;
}
@Override
public boolean hasNext() {
return n.next != null;
}
@Override
public Object next() {
n = n.next;
return n.item;
}
}
}
总结
N
的增多,比较的元素越多,时间复杂度为O(n)
N
的增多,查找的 元素越多,时间复杂度为O(n)
;提醒
其中对于双向链表遍历的边界值条件,如下代码
//获取指定位置i处的元素
public T get(int i){
Node node = head;
for (int index = 0 ; index<=i ; index++){
node = node.next;
}
return (T) node.item;
}
我们需要获取到i
处的元素,因为我们是从头节点head
开始遍历,所以其实我们的跳数也是从头节点开始计算,假设我们需要定位到2
号节点,从head
节点开始计算,index
设置为0
,我们刚好要移动3
次。即要定位i
处的元素,边界值判定条件恰好为i
黑马程序员Java数据结构与java算法全套教程