顺序表和链表
**数据结构:**组织和描述数据的一种方式
1.顺序表
1.1概念
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般采用集合(ArrayList)。
1.2接口实现
public class MyArrayList {
public int[] elem;
public int usedSize;
public MyArrayList() {
}
public MyArrayList(int capCity) {
this.elem = new int[capCity];
this.usedSize = 0;
}
//打印顺序表
public void display() {
for (int i = 0; i < this.usedSize; i++) {
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
//在pos位置新增data元素
public void add(int pos,int data) {
if (pos < 0 || pos > this.usedSize) {
System.out.println("pos位置添加不合法");
return;
}
if (this.usedSize == this.elem.length) {
System.out.println("顺序表为满");
return;
}
for (int i = this.usedSize - 1; i >= pos ; i--) {
this.elem[i + 1] = this.elem[i];
}
this.elem[pos] = data;
this.usedSize++;
}
//判断是否包含某个元素
public boolean contains(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i] == toFind) {
return true;
}
}
return false;
}
//查找某个元素对应的位置
public int search(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i] == toFind) {
return i;
}
}
return -1;
}
//获取pos位置元素
public int getPos(int pos) {
if (pos < 0 || pos > this.usedSize) {
System.out.println("pos位置添加不合法");
return -1;
}
return this.elem[pos];
}
//给pos位置的元素设置成value
public void setPos(int pos,int value) {
if (pos < 0 || pos > this.usedSize) {
System.out.println("pos位置添加不合法");
return;
}
this.elem[pos] = value;
}
//删除第一次出现的关键词key
public void remove(int key) {
int index = search(key);
if (index == -1) {
System.out.println("没有这个数字");
return;
}
for (int i = index; i < this.usedSize - 1; i++) {
this.elem[i] = this.elem[i + 1];
}
this.usedSize--;
}
//获取顺序表长度
public int size() {
return this.usedSize;
}
//清空顺序表
public void clear() {
this.usedSize = 0;
}
}
//测试
public static void main(String[] args) {
MyArrayList myArrayList = new MyArrayList(10);
myArrayList.add(0,0);
myArrayList.add(0,1);
myArrayList.add(0,2);
myArrayList.add(0,3);
myArrayList.add(0,4);
myArrayList.add(0,5);
myArrayList.add(0,6);
myArrayList.add(0,7);
myArrayList.add(0,8);
myArrayList.add(0,9);
myArrayList.display();//9 8 7 6 5 4 3 2 1
System.out.println(myArrayList.contains(0));//false
System.out.println(myArrayList.contains(1));//true
System.out.println(myArrayList.search(10));//-1
System.out.println(myArrayList.search(1));//8
System.out.println(myArrayList.getPos(2));//7
System.out.println(myArrayList.getPos(9));//0
// myArrayList.setPos(1,99);
// myArrayList.setPos(9,10);
// myArrayList.display();//9 99 7 6 5 4 3 2 1 10
myArrayList.remove(4);
myArrayList.remove(7);
// myArrayList.display();//9 99 6 5 3 2 1 10
System.out.println(myArrayList.size());//8
myArrayList.clear();
myArrayList.display();
}
2.链表
2.1概念
链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。链表是由一个节点一个节点组成的。
无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。
2.2链表实现
无头单向非循环链表实现
package mySingleLink;
class Node{
public int data;
public Node next;//存储对象的引用
public Node(int data) {
this.data = data;//这里没有初始化next的引用
}
}
public class MySingleLink {
public Node head;//定位头结点的引用
//头插法
public void addFirst(int data) {
//通过data构造一个Node的对象
Node node = new Node(data);
node.next = this.head;
this.head = node;
}
//尾插法
public void addLast(int data) {
Node node = new Node(data);
Node cur = this.head;
if (this.head == null) {
this.head = node;
return;
}
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
//找到index-1位置
public Node searchPrev(int index) {
int count = 0;
Node cur = this.head;
while (count < index - 1) {
cur = cur.next;
count++;
}
return cur;
}
//任意位置插入,第一个数据节点为0号下标
public void addIndex(int index,int data) {
Node node = new Node(data);
if (index < 0 || index > size()) {
System.out.println("index不合法");
return;
}
if (index == 0) {
addFirst(data);
return;
}
Node cur = searchPrev(index);
node.next = cur.next;
cur.next = node;
}
//查找是否包含关键字key是否在单链表当中
public boolean contains(int key) {
Node cur = this.head;
while (cur != null) {
if (cur.data == key) {
return true;
}
cur = cur.next;
}
return false;
}
//找到key的前驱
public Node searchPrevKey(int key) {
Node cur = this.head;
while (cur.next != null) {
if (cur.next.data == key) {
return cur;
}
cur = cur.next;
}
return null;
}
//删除第一次出现关键字为key的节点
public void remove(int key) {
if (this.head.data == key) {
this.head = this.head.next;
return;
}
Node prev = searchPrevKey(key);
if (prev == null) {
return;
}
Node del = prev.next;
prev.next = del.next;
}
//删除所有值为key的节点
public void removeAllKey(int key) {
if (this.head == null) {
return;
}
Node prev = this.head;
Node cur = this.head.next;
while (cur != null) {
if (cur.data == key) {
prev.next = cur.next;
//cur = cur.next;
} else {
prev = cur;
}
cur = cur.next;
}
if (this.head.data == key) {
this.head = this.head.next;
}
}
//得到单链表的长度
public int size() {
Node cur = this.head;
int count = 0;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
//打印链表
public void display() {
Node cur = this.head;
while (cur != null) {
System.out.print(cur.data+" ");
cur = cur.next;
}
System.out.println();
}
public void clear() {
this.head = null;
}
public static void main(String[] args) {
MySingleLink mySingleLink = new MySingleLink();
mySingleLink.addLast(1);
mySingleLink.addLast(2);
mySingleLink.addLast(3);
mySingleLink.addLast(4);
mySingleLink.addFirst(5);
mySingleLink.addFirst(4);
mySingleLink.addFirst(4);
//mySingleLink.display();
mySingleLink.addIndex(5,4);
//System.out.println(mySingleLink.size());
// mySingleLink.remove(999);
// mySingleLink.remove(99);
// mySingleLink.removeAllKey(4);
// mySingleLink.display();
}
}
jps:查看当前Java文件的进程号
jamp -histo:live 进程号
2.3练习题
1.删除链表中等于给定值 val 的所有节点。
public void removeAllKey(int key) {
if (this.head == null) {
return;
}
Node prev = this.head;
Node cur = this.head.next;
while (cur != null) {
if (cur.data == key) {
prev.next = cur.next;
//cur = cur.next;
} else {
prev = cur;
}
cur = cur.next;
}
if (this.head.data == key) {
this.head = this.head.next;
}
}
2.给定一个链表,判断链表中是否有环
public boolean hasCycle() {
Node fast = this.head;
Node slow = this.head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return false;
}
return true;
}
3.判断链表是否回文
public boolean chkPalindrome() {
if (this.head == null) {
return false;
}
//只有一个节点
if (this.head.next == null) {
return true;
}
//找到中间位置
Node fast = this.head;
Node slow = this.head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
//进行翻转
Node cur = slow.next;
while (cur != null) {
Node curNext = cur.next;
cur.next = slow;
slow = cur;
cur = curNext;
}
while (this.head != slow) {
if (this.head.data != slow.data) {
return false;
}
if (this.head.next == slow) {
return true;
}
this.head = this.head.next;
slow = slow.next;
}
return true;
}
4.删除链表重复节点
public Node deleteDuplication() {
Node cur = this.head;
Node newHead = new Node(-1);
Node temp = newHead;
while (cur != null) {
if (cur.next != null && cur.data == cur.next.data) {
while (cur.data == cur.next.data) {
cur = cur.next;
}
cur = cur.next;
} else {
temp.next = cur;
temp = temp.next;
cur = cur.next;
}
}
temp.next = null;
return newHead.next;
}
5.链表分割
public Node partition(int x) {
Node bs = null;
Node be = null;
Node as = null;
Node ae = null;
Node cur = this.head;
while (cur != null) {
if (cur.data < x) {
if (bs == null) {
bs = cur;
be = cur;
} else {
be.next = cur;
be = be.next;
}
} else {
if (as == null) {
as = cur;
ae = cur;
} else {
ae.next = cur;
ae = ae.next;
}
}
cur = cur.next;
}
if (bs == null) {
return as;
}
be.next = as;
if (as != null) {
ae.next = null;
}
return bs;
}
6.合并两个有序链表
public static Node mergeTwoLists(Node headA,Node headB) {
Node newHead = new Node(-1);
Node temp = newHead;
while (headA != null && headB != null) {
if (headA.data < headB.data) {
temp.next = headA;
temp = temp.next;
headA = headA.next;
} else {
temp.next = headB;
temp = temp.next;
headB = headB.next;
}
}
if (headA != null) {
temp.next = headA;
} else {
temp.next = headB;
}
return newHead.next;
}
7.输入一个链表,输出该链表中倒数第k个结点
public Node findKthToTail(int k) {
if (k < 0) {
return null;
}
Node fast = this.head;
Node slow = this.head;
while (k - 1 > 0) {
if (fast.next != null) {
fast = fast.next;
k--;
} else {
System.out.println("没有这个节点");
return null;
}
}
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
8.返回链表的中间结点
public Node middleNode() {
Node fast = this.head;
Node slow = this.head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}
9.反转一个单链表
public Node reverseList() {
Node cur = this.head;
Node newHead = null;
Node prev = null;
while (cur != null) {
Node curNext = cur.next;
if (curNext == null) {
newHead = cur;
}
cur.next = prev;
prev = cur;
cur = curNext;
}
return newHead;
}
10.给定一个链表,返回链表开始入环的第一个节点。
public Node detectCycle() {
Node fast = this.head;
Node slow = this.head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (fast == slow) {
break;
}
}
if (fast == null || fast.next == null) {
return null;
}
slow = this.head;
while (slow != fast) {
fast = fast.next;
slow = slow.next;
}
return slow;
}
11.//输入两个链表,找到他们的第一个公共节点
public Node getIntersectionNode(Node headA,Node headB) {
if (headA == null || headB == null) {
return null;
}
Node pl = headA;
Node ps = headB;
int lenA = 0;
while (pl != null) {
lenA++;
pl = pl.next;
}
int lenB = 0;
while (ps != null) {
lenB++;
ps = ps.next;
}
pl = headA;
ps = headB;
int len = lenA - lenB;
if (len < 0) {
pl = headB;
ps = headA;
len = lenB - lenA;
}
for (int i = 0; i < len; i++) {
pl = pl.next;
}
while (pl != ps && pl != null && ps != null) {
pl = pl.next;
ps = ps.next;
}
if (pl == ps && pl != null) {
return pl;
}
return null;
}
2.4无头双向链表的实现
package myDoubleList;
public class DoubleList {
public ListNode head;
public ListNode last;
//头插法
public void addFirst(int data) {
ListNode node = new ListNode(data);
if (this.head == null) {
this.head = node;
this.last = node;
} else {
node.next = this.head;
this.head.prev = node;
this.head = node;
}
}
//尾插法
public void addLast(int data) {
ListNode node = new ListNode(data);
if (this.head == null) {
this.head = node;
this.last = node;
} else {
this.last.next = node;
node.prev = this.last;
this.last = node;
}
}
//找到index的位置
public ListNode searchIndex(int index) {
if (index < 0 || index > size()) {
return null;
}
ListNode cur = this.head;
while (index != 0) {
cur = cur.next;
index--;
}
return cur;
}
//任意位置插入
public void addIndex(int index, int data) {
if (index == 0) {
addFirst(data);
return;
}
if (index == size()) {
addLast(data);
return;
}
ListNode node = new ListNode(data);
ListNode cur = searchIndex(index);
if (cur == null) {
return;
}
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;
}
//查找是否包含关键词key
public boolean contains(int key) {
ListNode cur = this.head;
while (cur != null) {
if (cur.data == key) {
return true;
}
cur = cur.next;
}
return false;
}
//删除第一次出现的关键词key
public void remove(int key) {
ListNode cur = this.head;
while (cur != null) {
if (cur.data == key) {
if (this.head.data == key) {
this.head = this.head.next;
this.head.prev = null;
} else {
cur.prev.next = cur.next;
if (cur.next != null) {
cur.next.prev = cur.prev;
} else {
this.last = this.last.prev;
}
}
return;
} else {
cur = cur.next;
}
}
}
//删除所有值为key的节点
public void removeAllKey(int key){
ListNode cur = this.head;
while (cur != null) {
if(cur.data == key) {
if(this.head.data == key) {
if(this.head.next == null) {
this.head = null;
return;
}
this.head = this.head.next;
this.head.prev = null;
}else {
cur.prev.next = cur.next;
if(cur.next!=null) {
cur.next.prev = cur.prev;
}else {
this.last = this.last.prev;
}
}
}
cur = cur.next;
}
}
public void removeAllKey2(int key){
ListNode cur = this.head;
while (cur != null) {
if(cur.data == key) {
if(cur == this.head) {
this.head = this.head.next;
this.head.prev = null;
}else {
cur.prev.next = cur.next;
if(cur.next!=null) {
//当前的cur不是最后一个节点
cur.next.prev = cur.prev;
}else {
this.last = this.last.prev;
}
}
}
cur = cur.next;
}
}
//得到链表的长度
public int size() {
int count = 0;
ListNode cur = this.head;
while (cur != null) {
count++;
cur = cur.next;
}
return count;
}
//打印链表
public void display() {
ListNode cur = this.head;
while (cur != null) {
System.out.print(cur.data+" ");
cur = cur.next;
}
System.out.println();
}
}