1.创建NodeDouble类
class NodeDouble<T> {
private T val;//数据域
private NodeDouble prev;//前驱节点
private NodeDouble next;//后继节点
private NodeDouble headNode = null;//头节点
private NodeDouble tailNode = null;//尾节点
// 构造方法
NodeDouble(T val) {
this.val = val;
}
}
2. 头插(addFirst)
// 头插
void addFirst(T val) {
NodeDouble node = new NodeDouble(val);
if (this.headNode == null) {
//如果是第一次插入:head和tail都相同
this.headNode = node;
this.tailNode = node;
} else {
node.next = this.headNode;//新结点的next存储head
this.headNode.prev = node;//旧的head结点prev域存储新node头结点的prev
this.headNode = node;//将node作为新的头结点
}
}
private static void testAddFirst() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addFirst(i);
}
node.display();
}
3. 尾插(addLast)
// 尾插
void addLast(T val) {
NodeDouble node = new NodeDouble(val);
if (this.headNode == null) {
this.headNode = node;
this.tailNode = node;
} else {
/*NodeDouble cur = this.headNode;
while (cur.next != null) {// 也可以使用单链表的形式找到尾巴再插入
cur = cur.next;
}
cur.next = node;
node.prev = cur;
this.tailNode = node;*/
this.tailNode.next = node;//把尾结点tail的next指向新的node结点
node.prev = this.tailNode;//新的node结点的prev存储旧tail尾结点
this.tailNode = node;//将node作为新tail结点
}
}
private static void testAddLast() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addLast(i);
}
node.display();
}
4. 任意位置插入(addIntex)
// 任意位置插入
void addIndex(int index, T val) {
NodeDouble node = new NodeDouble(val);
if (index == 0) {
addLast(val);
} else if (index == size()) {
addLast(val);
} else if (index > 0 && index < size()) {
NodeDouble cur = this.headNode;
while ((index - 1) != 0) {
cur = cur.next;
--index;
}
node.next = cur.next;
node.prev = cur;
cur.next = node;
} else {
throw new RuntimeException(index + "越界");
}
}
private static void testIndex() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addIndex(i, i);
}
node.display();
}
5. 删除第一次出现的 val(remove)
// 删除第一次出现的 val
void remove(T val) {
/*if (this.headNode.val == val) {//使用单链表的形式逐一删除
this.headNode = this.headNode.next;
this.headNode.prev = null;
} else {
NodeDouble cur = this.headNode;
while (cur.next != null) {
if (cur.next.val == val || cur.next.val.equals(val)) {
break;
}
cur = cur.next;
}
NodeDouble del = cur.next;
cur.next = del.next;
if (cur.next != null){
del.next.prev = cur;
}else{
this.tailNode = cur.prev;
}
}*/
NodeDouble cur = this.headNode;//使用双向链表的特性进行删除操作
while (cur != null) {
//防止尾结点的cur.next指向空指针异常
if (cur.val == val || cur.val.equals(val)) {
//找到了指定的 val 值节点
if (cur == this.headNode) {
//如果是头节点
this.headNode = this.headNode.next;//把之前的头结点的移动到头结点下一个结点
if (this.headNode == null){
//在判断目前的头节点是否为null
this.tailNode = null;// 说明新的头节点也是尾节点
}else{
this.headNode.prev = null;//说明新的头节点之后还有节点,把头节点的前驱置为 null
}
} else {
cur.prev.next = cur.next;//先把被删除节点前驱的后继绑定被删除节点的后驱
if (cur.next != null){
//在判断被删除的是不是尾结点[当cur.next==null则说明此cur是倒数第二个结点]
cur.next.prev = cur.prev;//前后前驱节点绑定
}else{
this.tailNode = cur.prev;//删除尾巴结点只需要移动tail
}
}
break;
}
cur = cur.next;
}
}
private static void testRemove() {
System.out.println("多个节点:");
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addLast(i);
node.addLast(5);
}
node.display();
node.remove(5);
node.display();
System.out.println("仅有一个节点:");
node = new NodeDouble(null);
node.addLast(5);
node.display();
node.remove(5);
node.display();
}
如图所示删除的是0x300这个节点的示意图
把0x200的next后继指向0x600;把0x600prev前驱指向0x200
6. 删除所有 val 相等的结点(removeAll)
// 删除所有 val 相等的结点
void removeAll(T val){
NodeDouble cur = this.headNode;
while(cur != null){
if (cur.val == val || cur.val.equals(val)){
// 判断是否需要删除头结点
if (cur == this.headNode){
this.headNode = this.headNode.next;
if (this.headNode == null){
this.tailNode = null;
}else{
this.headNode.prev = null;
}
}else{
cur.prev.next = cur.next;
if (cur.next != null){
cur.next.prev = cur.prev;
}else{
this.tailNode = cur.prev;
}
}
}
cur = cur.next;
}
}
private static void testRemoveAll() {
System.out.println("多个节点:");
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addLast(i);
node.addLast(5);
}
node.display();
node.removeAll(5);
node.display();
System.out.println("仅有一个节点:");
node = new NodeDouble(null);
node.addLast(5);
node.display();
node.removeAll(5);
node.display();
}
7. 长度(size)
// 长度
private int size() {
NodeDouble cur = this.headNode;
int len = 0;
while (cur != null) {
++len;
cur = cur.next;
}
return len;
}
8. 打印(display)
// 打印
void display() {
NodeDouble cur = this.headNode;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
9. 包含(contains)
// 包含
boolean contains(T val) {
NodeDouble cur = this.headNode;
while (cur != null) {
if (cur.val == val || cur.val.equals(val)) {
return true;
}
cur = cur.next;
}
return false;
}
private static void testContains() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 5; i++) {
node.addLast(i);
}
for (int i = 0; i < 10; i++) {
System.out.println(i + ": " + node.contains(i));
}
}
10. 清空(clear)
// 清空
void clear(){
NodeDouble cur = this.headNode;
while(this.headNode != null){
// 需要手动一个一个的删除后继和前驱
cur = cur.next;
this.headNode.prev = null;
this.headNode.next = null;
this.headNode = cur;
}
this.tailNode = null;
}
private static void testClear(){
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 5; i++) {
node.addLast(i);
}
node.display();
System.out.println("清空:");
node.clear();
node.display();
}
11. 完整代码
class NodeDouble<T> {
private T val;
private NodeDouble prev;
private NodeDouble next;
private NodeDouble headNode = null;
private NodeDouble tailNode = null;
NodeDouble(T val) {
this.val = val;
}
// 头插
void addFirst(T val) {
NodeDouble node = new NodeDouble(val);
if (this.headNode == null) {
this.headNode = node;
this.tailNode = node;
} else {
node.next = this.headNode;
this.headNode.prev = node;
this.headNode = node;
}
}
// 尾插
void addLast(T val) {
NodeDouble node = new NodeDouble(val);
if (this.headNode == null) {
this.headNode = node;
this.tailNode = node;
} else {
NodeDouble cur = this.headNode;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
node.prev = cur;
this.tailNode = node;
}
}
// 任意位置插入
void addIndex(int index, T val) {
NodeDouble node = new NodeDouble(val);
if (index == 0) {
addLast(val);
} else if (index == size()) {
addLast(val);
} else if (index > 0 && index < size()) {
NodeDouble cur = this.headNode;
while ((index - 1) != 0) {
cur = cur.next;
--index;
}
node.next = cur.next;
node.prev = cur;
cur.next = node;
} else {
throw new RuntimeException(index + "越界");
}
}
// 删除第一次出现的 val
void remove(T val) {
/*if (this.headNode.val == val) {
this.headNode = this.headNode.next;
this.headNode.prev = null;
} else {
NodeDouble cur = this.headNode;
while (cur.next != null) {
if (cur.next.val == val || cur.next.val.equals(val)) {
break;
}
cur = cur.next;
}
NodeDouble del = cur.next;
cur.next = del.next;
if (cur.next != null){
del.next.prev = cur;
}else{
this.tailNode = cur.prev;
}
}*/
NodeDouble cur = this.headNode;
while (cur != null) {
if (cur.val == val || cur.val.equals(val)) {
if (cur == this.headNode) {
this.headNode = this.headNode.next;
if (this.headNode == null) {
this.tailNode = null;
} else {
this.headNode.prev = null;
}
} else {
cur.prev.next = cur.next;
if (cur.next != null) {
cur.next.prev = cur.prev;
} else {
this.tailNode = cur.prev;
}
}
break;
}
cur = cur.next;
}
}
// 删除所有 val 相等的结点
void removeAll(T val) {
NodeDouble cur = this.headNode;
while (cur != null) {
if (cur.val == val || cur.val.equals(val)) {
// 判断是否需要删除头结点
if (cur == this.headNode) {
this.headNode = this.headNode.next;
if (this.headNode == null) {
this.tailNode = null;
} else {
this.headNode.prev = null;
}
} else {
cur.prev.next = cur.next;
if (cur.next != null) {
cur.next.prev = cur.prev;
} else {
this.tailNode = cur.prev;
}
}
}
cur = cur.next;
}
}
// 长度
private int size() {
NodeDouble cur = this.headNode;
int len = 0;
while (cur != null) {
++len;
cur = cur.next;
}
return len;
}
// 打印
void display() {
NodeDouble cur = this.headNode;
while (cur != null) {
System.out.print(cur.val + " ");
cur = cur.next;
}
System.out.println();
}
// 包含
boolean contains(T val) {
NodeDouble cur = this.headNode;
while (cur != null) {
if (cur.val == val || cur.val.equals(val)) {
return true;
}
cur = cur.next;
}
return false;
}
// 清空
void clear(){
NodeDouble cur = this.headNode;
while(this.headNode != null){
cur = cur.next;
this.headNode.prev = null;
this.headNode.next = null;
this.headNode = cur;
}
this.tailNode = null;
}
}
public class test {
private static void testAddFirst() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addFirst(i);
}
node.display();
}
private static void testAddLast() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addLast(i);
}
node.display();
}
private static void testIndex() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addIndex(i, i);
}
node.display();
}
private static void testRemove() {
System.out.println("多个节点:");
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addLast(i);
node.addLast(5);
}
node.display();
node.remove(5);
node.display();
System.out.println("仅有一个节点:");
node = new NodeDouble(null);
node.addLast(5);
node.display();
node.remove(5);
node.display();
}
private static void testRemoveAll() {
System.out.println("多个节点:");
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 10; i++) {
node.addLast(i);
node.addLast(5);
}
node.display();
node.removeAll(5);
node.display();
System.out.println("仅有一个节点:");
node = new NodeDouble(null);
node.addLast(5);
node.display();
node.removeAll(5);
node.display();
}
private static void testContains() {
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 5; i++) {
node.addLast(i);
}
for (int i = 0; i < 10; i++) {
System.out.println(i + ": " + node.contains(i));
}
}
private static void testClear(){
NodeDouble node = new NodeDouble(null);
for (int i = 0; i < 5; i++) {
node.addLast(i);
}
node.display();
System.out.println("清空:");
node.clear();
node.display();
}
public static void main(String[] args) {
// 放置测试用例
}
}