顺序表链表看这篇就够了

顺序表与链表

顺序表

image-20220501222401328

所谓的线性表,就是多个相同数据类型元素逻辑上呈直线排列,逻辑上连续。我们把这种结构称为线性表。

常见的线性表又:数组(顺序表),链表,栈,队列,字符串…

什么是动态数组呢?动态数组就是在普通数组上,增加了一个可以根据元素个数动态调整数组大小的功能。我们之前用的数最大问题就在于数组长度定长,一旦一个数组在定义时确定长度以后,使用过程中无法修改这个长度。

java中提供的数组都是静态数组定义之后无法改变长度,需要自己定义一个类,拓展基础数组的功能。

如何创建一个动态数组

public class MyArray {
        private int[] data;//数组
        private int size;//有效元素

        public MyArray() {//无参构造
            this(10);//调用有参构造
        }

        public MyArray(int initCap) {
            this.data = new int[initCap];//初始容量为10
        }

插入有效元素

我们不可能真正创建数组,当data数组满了我们就给他扩容。

public void add(int val) {
    this.data[size] = val;
    this.size++;
    //数组扩容
    if (this.size == this.data.length) {
        this.data = Arrays.copyOf(this.data, this.data.length * 2);
    }
}

在指定下标位置插入元素

思路就是将原本下标位置的元素向后移动,从最后一个元素开始移动。

//在某个下标插入一个元素
public void addIndex(int index, int val) {
    for (int i = size - 1; i >= index; i--) {
        this.data[i + 1] = this.data[i];
    }
    this.data[index] = val;
    this.size++;
}

查找数组中是否有val,返回下标

//查找数组中是否有val,返回下标
public int search(int val) {
    for (int i = 0; i < this.size; i++) {
        if (this.data[i] == val) {
            return i;//找到返回下标
        }
    }
    return -1;//没找到返回-1
}

将下标位置的值修改

//将下标位置的值修改
public void set(int index, int val) {//先判断下标的合法性
    if (index < 0 || index > size) {
        return;
    }
    this.data[index] = val;
}

删除指定下标的元素

//删除指定下标的元素
public void remove(int val) {
    int index = this.search(val);
    for (int i = index; i < size - 1; i++) {
        data[i] = data[i + 1];
    }
    size--;
}

链表

链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。

链表是由无数个节点相连组成的,可以想象成一列火车,每节车厢都是首位相连的。

每一个节点存储一个节点值val和下一个节点的地址值next。

单向不带头链表

image-20220424142730659

如何创建链表,首先需要创建一个节点类,节点类里面存储int val和Node next。

class Node {
    public int data;
    public Node next;
    public Node() {    //无参构造
        
    }
    public Node(int data) {  //有参构造
        this.data = data;
        this.next = null;
    }
    public Node(int data,Node node) {   //有参构造
        this.data = data;
        this.next = node;
    }
}

创建一个方法类,方法类里面首先定义一个头节点head,赋予默认值。

public class LinkedList {
    public Node head;
}

单向无头链表的增删查改。

向链表中插入节点

头插法代码示例

public class LinkedList {
    public Node head;
//头插法
public void addFirst(int data) {
    Node node = new Node(data);
    if(this.head == null) { //如果插入的是第一个节点,那么这个节点就是头节点
        this.head = node;
        return;
    }
    node.next = this.head; //如果不是,新插入节点的next=head
    this.head = node;
	}
}
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.addFirst(1);
        linkedList.addFirst(2);
        linkedList.addFirst(3);
        linkedList.addFirst(4);
        String ret = linkedList.toString();
        System.out.println(ret);

image-20220424145318673

尾插法代码示例

public class LinkedList {
	public Node head;
//尾插法
public void addList(int data) {
    Node node = new Node(data);
    if(this.head == null) {
        this.head = node;
        return;
    }
    Node cur = this.head;//新定义一个节点,从头开始遍历链表到尾部
    while(cur.next != null) {
        cur = cur.next;
    }
    cur.next = node;//把节点插入到最后一个节点尾部
	}
}
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.addList(1);
        linkedList.addList(2);
        linkedList.addList(3);
        linkedList.addList(4);
        String ret = linkedList.toString();
        System.out.println(ret);

image-20220424145904600

在指定下标位置插入

链表都是首位相连的,想把新节点插入到两个节点的中间,首先需要找到要插入位置的前一个节点,让新插入节点的next改为前一个节点的next值,将前一个节点的next值改为新插入的地址。这里一定要注意前后顺序,如果直接将前一个节点的next值改为新插入节点的地址,后面的节点地址就找不到了。

image-20220424153438594

public void addIndex(int index,int data) {
    if(index == 0) {//在0号下标位置插入新节点相当于头插法,直接调用即可
        this.addFirst(data);
        return;
    }
    if(index == this.size()) {//如果下标位置等于长度相当于尾插法,直接调用即可
        this.addList(data);
        return;
    }

    Node node = new Node(data);
    Node cur = search(index);//search是寻找下标的函数
    node.next = cur.next;
    cur.next = node;

}
//找到要插入位置的前一个节点
private Node search(int index) {
        if(index < 0 || index > this.size()) {//要注意下标位置的合法性
            throw new RuntimeException("index位置不合法");
        }
        Node cur = this.head;
        for(int i = 0; i < index - 1; i ++){
            cur = cur.next;
        }
        return cur;
    }

查找链表是否包含某个元素

public class LinkedList {
	public Node head;
//查看链表中是否包含这个元素
public boolean contains(int key) {
    Node cur = this.head;
    while(cur != null) {
        if(cur.data == key) { //如果有节点的值=要查找的值,返回true,否则返回false
            return true;
        }
        cur = cur.next;
    }
    return false;
	}
}
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.addList(1);
        linkedList.addList(2);
        linkedList.addList(3);
        linkedList.addList(4);
        System.out.println(linkedList.contains(2));//true
        System.out.println(linkedList.contains(5));//false

image-20220424150312673

修改给定下标位置节点的值,并返回修改前的值

public int set(int index,int data) {
        if(index < 0 || index > size()) {
            return -1;
        }
        Node cur = this.head;
        while(index != 0){
            cur = cur.next;
            index--;
        }
        int old = cur.data;
        cur.data = data;
        return old;
    }

删除给定下标位置的节点

删除是链表中最难的!!搞懂了删除其他的也就不难了

先说一下思路,想要删除一个节点只需要把删除节点的next赋值给前一个节点的next值,从而让这个节点和前后断开连接,还是需要先获得它的前一个节点

public int removeIndex(int index) {
    if(index < 0 || index >= size()) {//判断index是否合法
        return -1;
    }
    if (index == 0) {
        Node x = this.head;
        this.head = this.head.next;
        x.next = null;
        return x.data;
    }
    Node prev = this.head;//找前驱
    for (int i = 0; i < index-1; i++) {
        prev = prev.next;
    }
    Node node = prev.next;
    prev.next = node.next;
    node.next = null;
    return node.data;//我返回的是要删除节点的值

}

顺序表全代码

public class MyArray {
        private int[] data;//数组
        private int size;//有效元素

        public MyArray() {

            this(10);
        }

        public MyArray(int initCap) {

            this.data = new int[initCap];
        }

        //add插入有效元素
        public void add(int val) {
            this.data[size] = val;
            this.size++;
            //数组扩容
            if (this.size == this.data.length) {
                this.data = Arrays.copyOf(this.data, this.data.length * 2);
            }
        }

        public String toString() {
            String ret = "[";
            for (int i = 0; i < this.size; i++) {
                ret += this.data[i];
                if (i != this.size - 1) {
                    ret += ", ";
                }
            }
            ret += "]";
            return ret;
        }

        //在某个下标插入一个元素
        public void addIndex(int index, int val) {
            for (int i = size - 1; i >= index; i--) {
                this.data[i + 1] = this.data[i];
            }
            this.data[index] = val;
            this.size++;
        }

        //数组中是否包含这个数字
        public boolean contain(int val) {
            int index = this.search(val);
            if (index != -1) {
                return true;
            }
            return false;
        }

        //查找数组中是否有val,返回下标
        public int search(int val) {
            for (int i = 0; i < this.size; i++) {
                if (this.data[i] == val) {
                    return i;
                }
            }
            return -1;
        }

        //将下标位置的值修改
        public void set(int index, int val) {
            if (index < 0 || index > size) {
                return;
            }
            this.data[index] = val;
        }

        public boolean setVal(int oldVal, int newVal) {
            int index = search(oldVal);
            if (index != -1) {
                this.data[index] = newVal;
                return true;
            }
            return false;
        }
        //删除指定下标的元素
        public void remove(int val) {
            int index = this.search(val);
            for (int i = index; i < size - 1; i++) {
                data[i] = data[i + 1];
            }
            size--;
        }

        public void removeMore(int val) {
            for (int i = size - 1; i >= 0; i--) {
                if (this.data[i] == val) {
                    remove(val);
                }
            }
        }
    }

链表全代码

class Node {
    public int data;
    public Node next;
    public Node() {    //无参构造

    }
    public Node(int data) {  //有参构造
        this.data = data;
        this.next = null;
    }
    public Node(int data,Node node) {   //有参构造
        this.data = data;
        this.next = node;
    }
}
public class LinkedList {
    public Node head;
    //头插法
    public void addFirst(int data) {
        Node node = new Node(data);
        if(this.head == null) {
            this.head = node;
            return;
        }
        node.next = this.head;
        this.head = node;
    }
    //尾插法
    public void addList(int data) {
        Node node = new Node(data);
        if(this.head == null) {
            this.head = node;
            return;
        }
        Node cur = this.head;
        while(cur.next != null) {
            cur = cur.next;
        }
        cur.next = node;
    }
    //查看链表中是否包含这个元素
    public boolean contains(int key) {
        Node cur = this.head;
        while(cur != null) {
            if(cur.data == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    public int size() {
        int count = 0;
        Node cur = head;
        while(cur != null) {
            cur = cur.next;
            count++;
        }
        return count;
    }

    /**
     *  //任意位置插入,第一个数据节点为0号下标
     *
     *
     */
    public void addIndex(int index,int data) {
        if(index == 0) {
            this.addFirst(data);
            return;
        }
        if(index == this.size()) {
            this.addList(data);
            return;
        }

        Node node = new Node(data);
        Node cur = search(index);
        node.next = cur.next;
        cur.next = node;

    }
    private Node search(int index) {
        if(index < 0 || index > size()) {
            throw new RuntimeException("index位置不合法");
        }
        Node cur = this.head;
        for (int i = 0; i < index-1; i++) {
            cur = cur.next;
        }
//        while(index-1 != 0) {
//            cur = cur.next;
//            index--;
//        }
        return cur;
    }
    //要删除节点的前驱
    private Node searchPevr(int key) {
        Node pevr = this.head;
        while (pevr.next!= null) {
            if(pevr.next.data == key) {
                return pevr;
            }else {
                pevr = pevr.next;
            }
        }
        return null;
    }
    public int set(int index,int data) {
        if(index < 0 || index > size()) {
            return -1;
        }
        Node cur = this.head;
        while(index != 0){
            cur = cur.next;
            index--;
        }
        int old = cur.data;
        cur.data = data;
        return old;
    }
    public int removeIndex(int index) {
        if(index < 0 || index >= size()) {
            return -1;
        }
        if (index == 0) {
            Node x = this.head;
            this.head = this.head.next;
            x.next = null;
            return x.data;
        }
        Node prev = this.head;
        for (int i = 0; i < index-1; i++) {
            prev = prev.next;
        }
        Node node = prev.next;
        prev.next = node.next;
        node.next = null;
        return node.data;

    }

    /**
     * 删除第一次出现关键字为key的节点
     */
    public void remove(int key) {
        if(this.head == null) {
            return;
        }
        if(this.head.data == key) {
            this.head = this.head.next;
            return;
        }
        Node prev = searchPevr(key);
        if(prev == null) {
            System.out.println("没有这个节点");
            return;
        }
        Node del = prev.next;
        prev.next = del.next;
    }

    /***
     * 删除所有值为key的节点
     */
    public void removeAllkey(int key) {
        Node perv = this.head;
        Node cur = this.head.next;
        while(cur != null) {
            if(cur.data == key) {
                perv.next = cur.next;
                cur = cur.next;
            }else {
                perv = cur;
                cur = cur.next;
            }
        }
        if(this.head.data == key) {
            this.head = this.head.next;
        }
    }

    /**
     * 删除所有重复的元素
     */
    public Node deleteDuplicates() {
        Node dmmyhead = new Node();
        dmmyhead.next = head;
        Node prev = dmmyhead;
        Node cur = prev.next;
        while(cur != null) {
            Node next = cur.next;
            if(next == null) {
                break;
            }
            if(cur != null &&cur.data != next.data) {
                prev = prev.next;
                cur = cur.next;
            }else {
                while(cur.data == next.data) {
                    next = next.next;
                }
                prev.next = next;
                cur = next;
            }
        }
        return dmmyhead.next;

    }
    /**
     * 删除所有重复的元素,使每个元素只出现一次
     */
    public Node deleteDuplicates1(){
        if(this.head == null) {
            return this.head;
        }
        Node prev = this.head;
        Node cur = prev.next;
        while(cur != null) {
            if(prev.data == cur.data) {
                cur = cur.next;
            }else {
                prev.next = cur;
                prev = cur;
                cur = cur.next;
            }
        }
        prev.next = null;
        return head;
    }

    /***
     * 反转链表
     */
    public Node reverseList() {
        Node cur = this.head;
        Node prev = null;
        Node newHead = null;
        while(cur != null) {
            Node curNext = cur.next;
            if(curNext == null) {
                newHead = cur;
            }
            cur.next = prev;
            prev = cur;
            cur = curNext;
        }
        return newHead;
    }
    //打印
    public void display() {
        Node cur = this.head;
        while(cur != null) {
            System.out.print(cur.data+" ");
            cur = cur.next;
        }
        System.out.println();
    }
    public void disPlay1(Node ret) {
        Node cur = ret;
        while(cur != null) {
            System.out.print(cur.data+" ");
            cur = cur.next;
        }
        System.out.println();
    }
    public String toString() {
        String ret = "";
        while(head != null) {
            ret += head.data;
            ret += "->";
            head = head.next;
        }
        ret += "null";
        return ret;
    }

}

ead;
}
//打印
public void display() {
Node cur = this.head;
while(cur != null) {
System.out.print(cur.data+" “);
cur = cur.next;
}
System.out.println();
}
public void disPlay1(Node ret) {
Node cur = ret;
while(cur != null) {
System.out.print(cur.data+” ");
cur = cur.next;
}
System.out.println();
}
public String toString() {
String ret = “”;
while(head != null) {
ret += head.data;
ret += “->”;
head = head.next;
}
ret += “null”;
return ret;
}

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值