顺序表与链表
顺序表
所谓的线性表,就是多个相同数据类型元素逻辑上呈直线排列,逻辑上连续。我们把这种结构称为线性表。
常见的线性表又:数组(顺序表),链表,栈,队列,字符串…
什么是动态数组呢?动态数组就是在普通数组上,增加了一个可以根据元素个数动态调整数组大小的功能。我们之前用的数最大问题就在于数组长度定长,一旦一个数组在定义时确定长度以后,使用过程中无法修改这个长度。
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。
单向不带头链表
如何创建链表,首先需要创建一个节点类,节点类里面存储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);
尾插法代码示例
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);
在指定下标位置插入
链表都是首位相连的,想把新节点插入到两个节点的中间,首先需要找到要插入位置的前一个节点,让新插入节点的next改为前一个节点的next值,将前一个节点的next值改为新插入的地址。这里一定要注意前后顺序,如果直接将前一个节点的next值改为新插入节点的地址,后面的节点地址就找不到了。
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
修改给定下标位置节点的值,并返回修改前的值
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;
}
}