理论部分
- 理解线性表的定义与操作。
- 实现顺序表。
- 实现单链表、循环链表、双向链表。
接口实现
public interface LinearList<E> {
// 获取数据长度
int size();
// 获取容器的总长度
int capability();
// 是否为空
boolean isEmpty();
// 插入数据
void insert(E data);
// 指定位置插入数据
void insert(int index, E data);
// 删除最后一个数据
E remove();
// 删除指定位置的数据
E remove(int index);
// 修改
E replace(int index, E data);
// 查找指定位置的元素
E get(int index);
// 查找最后一个元素
E get();
}
顺序表
代码实现(Java)
public class SeqArrayList<E> implements LinearList<E>{
private int size;
private E[] datas;
public SeqArrayList(){
this(20);
}
public SeqArrayList(int capability){
datas = (E[]) new Object[capability];
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public int capability() {
return datas.length;
}
@Override
public boolean isEmpty() {
return size == 0;
}
// 扩大的数组的长度
private void resize(int capability){
if(capability <= 0)
return;
E [] temps = (E[]) new Object[capability];
for(int i = 0; i < size; i ++)
temps[i] = datas[i];
datas = temps;
}
@Override
public void insert(E data) {
insert(size, data);
}
@Override
public void insert (int index, E data) {
if(index < 0 || index > datas.length)
new IllegalArgumentException("index is invaild!");
if(size == datas.length)
resize(datas.length * 2);
for(int i = size; i > index; i --)
datas[i] = datas[i-1];
datas[index] = data;
size ++;
}
@Override
public E remove () {
E data = remove(size-1);
return data;
}
@Override
public E remove(int index) {
if(index < 0 || index > datas.length)
new IllegalArgumentException("index is invaild!");
if (size == datas.length/4)
resize (datas.length/2);
E data = datas[index];
for (int i = index; i < size-1; i++)
datas[i] = datas[i+1];
datas[size-1] = null;
size --;
return data;
}
@Override
public E replace(int index, E data) {
if(index < 0 || index > datas.length)
new IllegalArgumentException("index is invaild!");
E d = datas[index];
datas[index] = data;
return d;
}
@Override
public E get(int index) {
if(index < 0 || index > datas.length)
new IllegalArgumentException("index is invaild!");
return datas[index];
}
@Override
public E get() {
return get(size-1);
}
}
单链表
代码实现(Java)
public class SeqLinkedList<E> implements LinearList<E>{
private class Node{
E data;
Node next;
Node(E data){
this(data, null);
}
Node(E data, Node next){
this.data = data;
this.next = next;
}
}
// 虚拟头结点
private Node dummyHead;
private int size;
public SeqLinkedList(){
dummyHead = new Node(null);
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public int capability() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void insert(E data) {
dummyHead.next = new Node(data, dummyHead.next);
size ++;
}
@Override
public void insert(int index, E data) {
if(index < 0 || index > size)
new IllegalArgumentException("index is invaild!");
Node pre = dummyHead;
for (int i = 0; i < index; i ++)
pre = pre.next;
pre.next = new Node(data, pre.next);
size ++;
}
// 删除第一个元素
@Override
public E remove() {
return remove(0);
}
@Override
public E remove(int index) {
if(index < 0 || index > size)
new IllegalArgumentException("index is invaild!");
Node pre = dummyHead;
for(int i = 0; i < index; i ++)
pre = pre.next;
E data = pre.next.data;
pre.next = pre.next.next;
size --;
return data;
}
@Override
public E replace(int index, E data) {
Node cur = dummyHead.next;
for(int i = 0; i < index; i ++)
cur = cur.next;
E d = cur.data;
cur.data = data;
return d;
}
public void print(){
Node cur = dummyHead;
while(cur.next != null){
cur = cur.next;
System.out.print(cur.data);
if(cur.next != null)
System.out.print("->");
}
}
// 指定位置的元素
@Override
public E get(int index) {
Node cur = dummyHead.next;
for(int i = 0; i < index; i ++)
cur = cur.next;
return cur.data;
}
// 返回链表第一个元素
@Override
public E get() {
return get(0);
}
}
循环双链表
代码实现(Java)
public class LoopLinkedList<E> implements LinearList<E> {
private class Node {
E data;
Node next;
Node(E data) {
this(data, null);
}
Node(E data, Node next) {
this.data = data;
this.next = next;
}
}
private Node head;
private int size;
private Node tail;
LoopLinkedList() {
head = null;
tail = null;
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public int capability() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void insert(E data) {
insert(size, data);
}
@Override
public void insert(int index, E data) {
if (head == null) {
System.out.println("head is null " + data);
head = new Node(data);
tail = head;
} else if (index == 0) {
System.out.println("index == 0 " + data);
head = new Node(data, head);
tail.next = head;
} else if (index == size) {
System.out.println("index == size :" + data);
tail.next = new Node(data, head);
tail = tail.next;
} else {
Node pre = head;
for (int i = 0; i < index - 1; i++)
pre = pre.next;
pre.next = new Node(data, pre.next);
}
size++;
}
@Override
public E remove() {
return remove(size - 1);
}
@Override
public E remove(int index) {
E d;
if (index == 0) {
d = head.data;
head = head.next;
tail.next = head;
} else {
Node pre = head;
for (int i = 0; i < index - 1; i++)
pre = pre.next;
d = pre.next.data;
pre.next = pre.next.next;
}
size--;
return d;
}
@Override
public E replace(int index, E data) {
E d;
Node cur = head;
for (int i = 0; i < index; i++)
cur = cur.next;
d = cur.data;
cur.data = data;
return data;
}
public E get(int index) {
Node cur = head;
for (int i = 0; i < index; i++)
cur = cur.next;
//System.out.print();
return cur.data;
}
@Override
public E get() {
return get(size - 1);
}
}
双链表
代码实现(Java)
public class DLinkedList<E> implements LinearList<E>{
private class Node{
E data;
Node next;
Node pre;
Node(E data){
this(data, null, null);
}
Node(E data, Node pre, Node next){
this.data = data;
this.pre = pre;
this.next = next;
}
}
private Node head;
//private Node tail;
private int size;
public DLinkedList(){
head = null;
size = 0;
}
@Override
public int size() {
return size;
}
@Override
public int capability() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
// 向 head 插入数据
@Override
public void insert(E data) {
insert(0 , data);
}
// 任意指定位置插入数据
@Override
public void insert(int index, E data) {
if(head == null){
head = new Node(data);
}else if(index == 0){
Node node = new Node(data, null, head);
head.pre = node;
head = node;
}else {
Node preNode = head;
for(int i = 0; i < index - 1; i ++)
preNode = preNode.next;
preNode.next = new Node(data, preNode, preNode.next);
}
size ++;
}
// 删除第一个元素
@Override
public E remove() {
return remove(0);
}
@Override
public E remove(int index) {
E d;
if (index == 0){
d = head.data;
head = head.next;
head.pre = null;
}else {
Node preNode = head;
for(int i = 0; i < index - 1; i ++)
preNode = preNode.next;
Node delNode = preNode.next;
preNode.next = delNode.next;
delNode.next.pre = preNode;
d = delNode.data;
delNode = null;
}
size --;
return d;
}
// 指定位置替换数据,返回旧的数据
@Override
public E replace(int index, E data) {
Node cur = head;
for(int i = 0; i < index; i ++)
cur = cur.next;
E d = cur.data;
cur.data = data;
return d;
}
@Override
public E get(int index) {
Node cur = head;
for(int i = 0; i < index; i++)
cur = cur.next;
return cur.data;
}
// 返回第一个元素
@Override
public E get() {
return get(0);
}
public void nextPrint(){
Node cur = head;
for(int i = 0; i < size; i ++){
System.out.print(cur.data + " ");
if(i != size - 1)
System.out.print("->");
cur = cur.next;
}
System.out.println();
}
public void prePrint(){
Node cur = head;
for(int i = 0; i < size - 1 ; i ++)
cur = cur.next;
Node pre = cur;
for(int i = 0; i < size ; i ++){
System.out.print(pre.data + " ");
pre = pre.pre;
if (i != size-1)
System.out.print("->");
}
}
}
练习部分
1. 合并两个有序链表
https://leetcode-cn.com/problems/merge-two-sorted-lists/
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
代码实现:
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode newList = null;
ListNode tail = null;
while(l1 != null && l2 != null){
int data = -1;
if(l1.val < l2.val){
data = l1.val;
l1 = l1.next;
}else if(l2.val < l1.val){
data = l2.val;
l2 = l2.next;
}else{
data = l1.val;
l1 = l1.next;
}
ListNode node = new ListNode(data);
if(newList == null){
newList = node;
tail = newList;
}else{
tail.next = node;
tail = node;
}
}
// 合并 l1 剩下的数据
while(l1 != null){
ListNode node = new ListNode(l1.val);
l1 = l1.next;
if(newList == null){
newList = node;
tail = newList;
}else{
tail.next = node;
tail = node;
}
}
// 合并 l2 剩下的数据
while(l2 != null){
ListNode node = new ListNode(l2.val);
l2 = l2.next;
if(newList == null){
newList = node;
tail = newList;
}else{
tail.next = node;
tail = node;
}
}
return newList;
}
}
2. 删除链表的倒数第N个节点
https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
代码实现
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int num = calculate(head);
ListNode pre = head;
if(num - n == 0){
head = head.next;
}else {
for (int i = 0; i < num - n - 1; i++)
pre = pre.next;
pre.next = pre.next.next;
}
return head;
}
private int calculate(ListNode head){
ListNode node = head;
int num = 0;
while(node != null){
num ++;
node = node.next;
}
return num;
}
}
3. 旋转链表
https://leetcode-cn.com/problems/rotate-list/
给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
代码实现
class Solution {
public ListNode rotateRight(ListNode head, int k) {
int len = calculate(head);
ListNode tail = null;
if(len == 0)
return head;
int rotateNum = k % len;
for(int i = 0; i < rotateNum; i++){
ListNode pre = head;
for(int j = 0; j < len - 2; j ++)
pre = pre.next;
tail = pre.next;
tail.next = head;
head = tail;
pre.next = null;
}
return head;
}
private int calculate(ListNode head){
ListNode node = head;
int num = 0;
while(node != null){
num ++;
node = node.next;
}
return num;
}
}