数据结构(一)

概述

数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。(通俗来讲就是数据在计算机上是如何组织和存储)

按照数据结构中元素的相互关系可以分为4类:集合,线性结构,树形结构,图或网状结构。
在这里插入图片描述

1.集合:结构中的元素除了同属于一个集合外无其他关系。

2.线性结构:线性元素之间存在一个对一个的关系。

3.树形结构:结构中元素之间存在一对多的关系。

4图或网状结构:结构中的元素存在多对多的关系。

以下将分为三个部分来说明常见的数据结构

1.线性表(数组,链表,栈,队列)以及特殊的散列表(也叫哈希表)

2.树(二叉树,二叉排序树,二叉搜索树,平衡二叉树,红黑树,最优二叉树(哈夫曼树),B树等)

3.图(最小生成树,最短路径问题)

线性表

线性表是n个数据元素的有限序列。

数组

具有一段连续(物理上或者逻辑上)的内存,存储同一种类型数据的集合,数组其实就是一个容器。

java实现数组

数组包含的方法:

1.增:依次插入元素(add)

2.删:根据数组下标删除(deleteByIndex),根据值删除(deleteByValue)

3.改:根据数组下标修改值(modify)

4.查:查询数组中是否包含该值(searchByValue)

5.辅助函数:打印数组(printArr)

public class MyArray {
    private int arr[];
    /**
    *currentIndex:当前数组最后一个元素的索引
    *capacity:数组的容量
    */
    private int currentIndex = -1;
    private int capacity = 0;
    private boolean flag = false;

    /**
     * 构造方法,默认构造数组大小为10
     */
    public MyArray() {
        arr = new int[10];
        capacity = 10;
    }

    public MyArray(int size) {
        arr = new int[size];
        capacity = size;
    }

    /**
      * 1.增(依次插入元素)
      */
    public void add(int value) {
        if (currentIndex < capacity - 1) {
            arr[++currentIndex] = value;
        } else {
            System.out.println("数组已满,无法继续插入!");
        }
    }

    /**
      * 2.删(通过下标删除,判断索引如果越界抛出异常,删除成功返回true,失败返回false)
      * 
      * @param index 待删除元素的数组下标
      */
    public boolean deleteByIndex(int index) {
        if (index < 0 || index >= capacity) {
            throw new ArrayIndexOutOfBoundsException();
        } else {
            for (int i = index; i <= currentIndex - 1; i++) {
                arr[i] = arr[i + 1];
            }
            currentIndex--;
            flag = true;
            return flag;
        }
    }

    /**
    * 2.删(通过数值删除,如果数组中包含值就删除,不包含就打印信息)
    * 
    * @param value:待删除的元素
    */
    public boolean deleteByValue(int value) {
        int index;
        if ((index = this.searchByValue(value)) == -1) {
            System.out.println("数组中不包含" + value);
            flag = false;
        } else {
            this.deleteByIndex(index);
            flag = true;
        }
        return flag;
    }

    /**
    * 3.改
      */
    public boolean modify(int index, int value) {
        if (index < 0 || index >= capacity) {
            throw new ArrayIndexOutOfBoundsException();
        } else {
            arr[index] = value;
            flag = true;
        }
        return flag;
    }

    /**
    * 4.查(查询值是否存在数组中,存在返回值的下标,不存在返回-1)
      */
    public int searchByValue(int value) {
        int i = 0;
        for (; i < capacity; i++) {
            if (arr[i] == value) {
                break;
            }
        }
        if (i == capacity) {
            i = -1;
        }
        return i;
    }

   /**
    * 5.打印数组
    * */
    public void printArr() {
        System.out.println("数组容量:" + capacity + ", 当前元素数量:" + (currentIndex + 1));
        System.out.print("arr={");
        for (int i = 0; i <= currentIndex; i++) {
            if (i == currentIndex) {
                System.out.println(arr[i] + "}");
            } else {
                System.out.print(arr[i] + ",");
            }
        }
    }

数组的特点:

1.数组中储存的元素必须是相同的类型。

2.长度固定,在内存中占据连续空间。

3.存值取值快,只需提供相应的索引值,时间复杂度为O(1),增删需要移动插入元素后元素,时间复杂度为O(N),无序数组的查找必须遍历数组元素值,因此时间复杂度为O(N)。

数组适用情况:

储存的元素都是相同的类型,且数组大小固定,存取值较多,增删,查找较少的情况。

有序数组

有序数组数组就是指数组中的元素是按一定的规则排列的,这样在查找时可以利用二分查找极大提升了查找的效率。有序数组的缺点也相当明显,当插入一个元素时,需要确定待插入元素的下标,然后对其后的元素进行后移一位处理,所以插入效率不高。

需要修改数组实现中的添加add,二分查找searchByValue方法:

public void add(int value) {
		int location = -1;
		// 判断数组是否已满
		if (currentIndex < capacity - 1) {
			// 数组为空时,索引为0
			if (currentIndex == -1) {
				location = 0;
			} else {
				// 遍历数组,找到第一个大于value的值,此时i即为插入的下标
				for (int i = 0; i <= currentIndex; i++) {
					if (value < arr[i]) {
						location = i;
						break;
					}
				}
				// 如果没有找到,说明value应该插入到数组末尾
				if (location == -1) {
					location = currentIndex + 1;
				}
			}
			// 依次将location后面的元素后移一位
			for (int i = currentIndex; i >= location; i--) {
				arr[i + 1] = arr[i];
			}
			// 插入value更新currentIndex
			arr[location] = value;
			currentIndex++;
		} else {
			System.out.println("数组已满,无法继续插入!");
		}
	}

/**
	 * 4.查找方法,使用二分查找,如果找到就返回下标值,如果没有就返回-1
	 */
	public int find(int target) {
		int index = -1;
		int begin = 0;
		int end = currentIndex;
		while (true) {
			int mid = (begin + end) / 2;
			// 如果相等说明找到了
			if (arr[mid] == target) {
				index = mid;
				break;
				// 如果mid和begin重合,说明区间内只含两个元素,只需比较arr[end]和target,退出循环
			} else if (mid == begin) {
				if (arr[end] == target) {
					index = end;
				}
				break;
				// 如果arr[mid]和target不相等,且mid与begin不相等说明此时区间内至少含有三个数,
				// 判断arr[mid]与target的大小,更新区间
			} else {
				if (arr[mid] > target) {
					end = mid;
				} else {
					begin = mid;
				}
			}
		}
		return index;
	}

注:

实现数组有序的是插入方法,在插入的时候先找到该元素合适的下标再进行插入操作。

因为数组已经有序,查找方法用二分查找实现。

因为数组已经有序,删除一个数后,剩下的数组依然有序。

对数组值进行修改相当于先删除待修改的值,然后调用add方法插入修改后的值。

有序数组特点:

存取值快,时间复杂度O(1);使用二分查找,查找的时间复杂度为O(logN);插入,修改操作需要移动元素,时间复杂度为O(N)

适用情况:查找,存取值频繁,插入,删除操作较少。

链表

链表中的每个节点都包含了数据域和引用(指针域),其中数据域储存了数据,而引用(指针域)指向了下一个节点所在的位置,这样节点就通过引用(指针域)连接起来构成了链表。

单链表

单链表中每个节点均指向其后一个节点,而后面节点没有它前驱节点的信息,头节点无前驱节点,尾节点无后继节点(指向null),也可以理解为单链表是从头到尾单方向传递的。

链表示意图:

在这里插入图片描述
单链表的操作:

1.插入

插入分为三种情况,即头节点前插入,尾节点后插入,其他位置插入

头节点前插入
在这里插入图片描述
尾节点后插入
在这里插入图片描述
其他节点插入
在这里插入图片描述
2.删除

删除节点分为三种情况,删除头节点,删除尾节点,删除其他位置节点

删除头节点

在这里插入图片描述

删除尾节点在这里插入图片描述

删除其他节点
在这里插入图片描述

单链表Java实现

单链表包含的方法:

1.增:在第一个节点前面添加节点(addFirst),在指定节点前(后)插入新节点(insAfter,insBefore)。

2.删:删除第一个节点(delFirst),删除指定的节点(delByData)

3.改:修改指定节点的数值(modifyByValue)

4.查:查找值对应的节点(SearchByData),查找值对应的父节点(getParent)

5.辅助函数:判断链表是否为空(isEmpty),链表是否包含该数值(containsData),打印链表(PrintLList)

//封装节点
public class LNode {

	public int data;
	public LNode next;

	public LNode(int data) {
		this.data = data;
	}

	public LNode() {
	}
}
//单链表实现
public class MyLinkedList {
	private LNode first;

	public MyLinkedList() {
		first = null;
	}

	/**
	 * 1.增,向头节点前插入节点,成功返回节点node
	 */
	public LNode addFirst(LNode node) {
		node.next = first;
		first = node;
		return node;
	}

	/**
	 * 1.增,在target后插入node节点,插入成功返回node节点!
	 */
	public LNode insAfter(int target, LNode node) throws Exception {
		LNode temp;
		LNode cur;
		cur = this.searchByData(target);
		temp = cur.next;
		cur.next = node;
		node.next = temp;
		return node;
	}

	/**
	 * 1.增,在target前插入node节点,插入成功返回node节点!
	 */
	public LNode insBefore(int target, LNode node) throws Exception {
		LNode cur;
		LNode pre;
		cur = this.searchByData(target);
		pre = this.getParent(target);
		pre.next = node;
		node.next = cur;
		return node;
	}

	/**
	 * 2.删,删除第一个节点,成功返回删除的节点对象
	 */
	public LNode delFirst() throws Exception {
		if (this.isEmpty()) {
			throw new Exception("链表为空!不能删除!");
		}
		LNode temp = new LNode();
		temp = first;
		first = first.next;
		return temp;
	}

	/**
	 * 2.删,删除指定的节点,成功返回被删除的节点
	 */
	public LNode delByData(int target) throws Exception {
		LNode cur;
		LNode pre;
		cur = this.searchByData(target);
		pre = this.getParent(target);
		pre.next = cur.next;
		return cur;
	}

	/**
	 * 3.改,修改指定节点的值
	 */
	public LNode modifyByValue(int target, int value) throws Exception {
		LNode cur;
		cur = this.searchByData(target);
		cur.data = value;
		return cur;
	}

	/**
	 * 4.查,由data值查找LNode的位置
	 */
	public LNode searchByData(int target) throws Exception {
		LNode temp = first;
		while (temp != null) {
			if (temp.data == target) {
				break;
			}
			temp = temp.next;
		}
		return temp;
	}

	/**
	 * 4.查,查找target元素对应的父节点,找到就返回父节点,不存在就抛出异常!
	 */
	public LNode getParent(int target) throws Exception {
		if (!this.containsData(target)) {
			throw new Exception("链表中不包含该值对应的节点!");
		}
		LNode pre = first;
		// 第一个元素无parent
		while (pre.next != null) {
			if (pre.next.data == target) {
				break;
			}
			pre = pre.next;
		}
		return pre;
	}

	/**
	 * 判断链表是否为空,头节点为空则链表为空。
	 */
	public boolean isEmpty() {
		return first == null;
	}

	/**
	 * 打印链表
	 */
	public void printLList() {
		LNode ln = first;
		System.out.print("{");
		while (ln != null) {
			if (ln.next == null) {
				System.out.println(ln.data + "}");
				break;
			}
			System.out.print(ln.data + ",");
			ln = ln.next;
		}
	}

	/**
	 * 链表是否包含node
	 */
	public boolean containsData(int target) {
		LNode ln = first;
		while (ln != null) {
			if (ln.data == target) {
				return true;
			}
			ln = ln.next;
		}
		return false;
	}

单链表特点

插入(链表末尾插入),删除快,只需要操插入和删除节点前后节点的引用即可完成,数据复杂度为O(1)。

存取值,查找慢,由于单链表后续节点无其前驱节点的信息,所以存取值和查找都必须从头节点开始依次向后寻找,时间复杂度为O(N)。

适用情况:增删较多,查询少,存取少。

双端链表

与单链表比较相似,不同的是在他的头节点加入了一个对尾节点的引用。(注:双端链表与双向链表是不同的)

在这里插入图片描述

特点:与单链表最大的不同是保存了尾节点的引用,不需要从头遍历获取尾节点,方便在最后的节点进行插入操作(如队列)。

双端链表的Java实现

对比单链表增加了一个尾节点引用last,需要修改单链表addFirst,delFirst方法,增加addLast,delLast(效率不高)方法,其他单链表方法也可以使用。

public class DoubleSideLinkedList {
    //首尾节点的引用
	private LNode first;
	private LNode last;
	/**
	 * 1.增,向头节点前插入节点,成功返回节点node
	 */
	public LNode addFirst(LNode node) {
		if (this.isEmpty()) {
			last = node;
		}
		node.next = first;
		first = node;
		return node;
	}
    /**
	 * 1.增,在尾部插入节点
	 */
	public LNode addLast(LNode node) {
		if (this.isEmpty()) {
			first = node;
		}
		last.next = node;
		last = node;
		node.next = null;
		return node;
	}
	
	/**
	 * 2.删,删除第一个节点,成功返回删除的节点对象
	 */
	public LNode delFirst() throws Exception {
		LNode temp = new LNode();
		if (this.isEmpty()) {
			throw new Exception("链表为空!不能删除!");
		} else if (first == last) {
			// 如果只有一个节点
			temp = first;
			first = null;
			last = null;

		} else {
			// 两个节点及以上
			temp = first;
			first = first.next;
		}
		return temp;
	}
    /**
	 * 2.删,删除尾节点
	 */
	public LNode delLast() throws Exception {
		LNode temp = new LNode();
		if (this.isEmpty()) {
			throw new Exception("链表为空!不能删除!");
		} else if (first == last) {
			// 如果只有一个节点
			temp = last;
			first = null;
			last = null;

		} else {
			// 两个节点及以上
			LNode pre = this.getParent(last.data);
			temp = last;
			pre.next = null;
			last = pre;
		}![在这里插入图片描述](https://img-blog.csdnimg.cn/20200511004349426.png#pic_center)
		return temp;
	}
}

双向链表

相对于单向链表,双向链表中节点包含了前驱节点引用和后续节点引用,因此查找其前驱节点不必从头节点遍历。

双向链表节点
在这里插入图片描述

双向链表示意图

在这里插入图片描述

双向链表的插入

在这里插入图片描述
双向链表的删除

在这里插入图片描述

双向链表的Java实现

1.双向链表中包含前后节点的引用,所以不需要getParent函数,直接通过prior和next引用访问前后节点。

2.插入分为根据指定的节点前插入和后插入。

封装双向链表的节点

public class DLNode {
	public int data = 0;
	DLNode prior;
	DLNode next;

	public DLNode() {
	}

	public DLNode(int data) {
		this.data = data;
	}
}

双向链表的实现

public class DoubleLinkedList {
	private DLNode first;
	private DLNode last;

	public DoubleLinkedList() {
		first = null;
		last = null;
	}

	/**
	 * 1.增:添加第一个节点
	 */
	public DLNode addFirst(DLNode node) {
		first = node;
		last = node;
		node.next = null;
		node.prior = null;
		return node;
	}

	/**
	 * 1.增:前插入节点,循环链表的任何节点都有父节点,所以不需要做处理(单个节点的父节点是自身)
	 */
	public DLNode insBefore(int target, DLNode node) throws Exception {
		DLNode pre;
		DLNode cur;
		cur = this.searchByData(target);
		pre = cur.prior;
		// 如果pre是null说明在头节点前面插入
		if (cur == first) {
			node.next = first;
			first.prior = node;
			node.prior = null;
			// 更新first
			first = node;
		} else {
			pre.next = node;
			node.prior = pre;
			node.next = cur;
			cur.prior = node;
		}
		return node;
	}

	/**
	 * 1.增:后插入节点,循环链表的任何节点都有父节点,所以不需要做处理(单个节点的父节点是自身)
	 */
	public DLNode insAfter(int target, DLNode node) throws Exception {
		DLNode aft;
		DLNode cur;
		cur = this.searchByData(target);
		aft = cur.next;
		// 当在last节点后插入节点时需要更新last
		if (cur == last) {
			cur.next = node;
			node.prior = cur;
			node.next = null;
			// 更新last
			last = node;
		} else {
			cur.next = node;
			node.prior = cur;
			aft.prior = node;
			node.next = aft;
		}
		return node;
	}

	/**
	 * 2.删,删除指定的节点,成功返回被删除的节点
	 */
	public DLNode delByData(int target) throws Exception {
		DLNode temp;
		if (!this.containsData(target)) {
			throw new Exception("该链表不包含此节点,无法删除!");
		}
		// 链表为空
		if (this.isEmpty()) {
			throw new Exception("链表为空,无法删除!");
		} else if (first == last) {
			// 链表只有一个元素的情况
			temp = first;
			first = null;
			last = null;
		} else {
			// 链表有两个和两个以上的节点
			DLNode cur = this.searchByData(target);
			temp = cur;
			// 删除的为头节点
			if (cur == first) {
				DLNode aft = cur.next;
				aft.prior = null;
				first = aft;
				// 删除的为尾节点
			} else if (cur == last) {
				DLNode pre = cur.prior;
				pre.next = null;
				last = pre;
				// 删除其他节点
			} else {
				DLNode pre = cur.prior;
				DLNode aft = cur.next;
				pre.next = aft;
				aft.prior = pre;
			}
		}
		return temp;
	}

	/**
	 * 3.改,修改指定节点的值
	 */
	public DLNode modifyByValue(int target, int value) throws Exception {
		if (!this.containsData(target)) {
			throw new Exception("该节点不存在链表中,无法修改!");
		}
		DLNode cur;
		cur = this.searchByData(target);
		cur.data = value;
		return cur;
	}

	/**
	 * 4.查,由data值查找LNode的位置
	 */
	public DLNode searchByData(int target) throws Exception {
		DLNode temp = first;
		while (temp != null) {
			if (temp.data == target) {
				break;
			}
			temp = temp.next;
		}
		return temp;
	}

	/**
	 * 判断链表是否为空,头节点为空则链表为空。
	 */
	public boolean isEmpty() {
		return first == null;
	}

	/**
	 * 链表是否包含node
	 */
	public boolean containsData(int target) {
		boolean flag = false;
		DLNode dln = first;
		while (dln != null) {
			if (dln.data == target) {
				flag = true;
				break;
			}
			dln = dln.next;
		}
		return flag;
	}

	/**
	 * 打印链表
	 */
	public void printLList() {
		if (this.isEmpty()) {
			System.out.println("链表为空!");
			return;
		}
		DLNode ln = first;
		while (ln != null) {
			if (ln.next == null) {
				System.out.println(ln.data);
				break;
			}
			System.out.print(ln.data + "->");
			ln = ln.next;
		}
	}

单向循环链表

循环链表分为单向循环链表和双向循环链表。

单向循环链表:将单链表的尾节点的next引用指向链表头而不是null,即让单链表的尾和头相连接就构成了单向循环链表。

在这里插入图片描述

1.增

添加第一个节点,链表中只含有一个节点时,其后继节点使其自身

在这里插入图片描述
在队尾插入
在这里插入图片描述

在其他位置插入
在这里插入图片描述

单向循环链表Java实现
public class CycleLinkedList {
	private LNode first;
	private LNode last;
    public CycleLinkedList() {
            first = null;
            last = null;
        }
    /**
	 * 1.增,创建第一个节点
	 */
	public LNode addFirst(LNode node) {
		first = node;
		last = node;
		node.next = first;
		return node;
	}

	/**
	 * 1.增,插入节点,循环链表的任何节点都有父节点,所以不需要做处理(单个节点的父节点是自身)
	 */
	public LNode insBefore(int target, LNode node) throws Exception {
		LNode pre;
		LNode cur;
		pre = this.getParent(target);
		cur = pre.next;
		pre.next = node;
		node.next = cur;
		// 如果要在第一个节点前插入节点,更新尾节点
		if (pre == last) {
			last = node;
		}
		return node;
	}

	/**
	 * 1.增,在target后插入node节点,插入成功返回node节点! 同理,循环链表的任意节点都包含后继节点,单个节点的后继节点是其自身
	 */
	public LNode insAfter(int target, LNode node) throws Exception {
		LNode aft;
		LNode cur;
		cur = this.searchByData(target);
		aft = cur.next;
		cur.next = node;
		node.next = aft;
		// 如果在最后一个节点后面插入节点,更新尾节点
		if (cur == last) {
			last = node;
		}
		return node;
	}

	/**
	 * 2.删,删除指定的节点,成功返回被删除的节点
	 */
	public LNode delByData(int target) throws Exception {
		LNode temp;
		if (!this.containsData(target)) {
			throw new Exception("该链表不包含此节点,无法删除!");
		}
		// 链表为空
		if (this.isEmpty()) {
			throw new Exception("链表为空,无法删除!");
		} else if (first == last) {
			// 链表只有一个元素的情况
			temp = first;
			first = null;
			last = null;
		} else {
			// 链表有两个和两个以上的节点
			LNode cur;
			LNode pre;
			cur = this.searchByData(target);
			pre = this.getParent(target);
			temp = cur;
			pre.next = cur.next;
		}
		return temp;
	}
	/**
	 * 4.查,查找target元素对应的父节点,找到就返回父节点,不存在就抛出异常!
	 */
	public LNode getParent(int target) throws Exception {
		if (!this.containsData(target)) {
			throw new Exception("链表中不包含该值对应的节点!");
		}
		// 头节点的父节点为尾节点
		if (target == first.data) {
			return last;
		} else {
			LNode pre = first;
			LNode cur = first.next;
            //因尾节点指向头节点,所以不能再用cur!=null来判断,而应当使用cur!=first
			while (cur != first) {
				if (cur.data == target) {
					break;
				}
				pre = pre.next;
				cur = cur.next;
			}
			return pre;
		}
	}
    
	/**
	 * 打印链表
	 */
	public void printLList() {
		LNode ln = first;
		// 打印第一个节点信息
		System.out.print(ln.data);
		ln = ln.next;
        //打印的判断条件也需要调整
		while (ln != first) {

			System.out.print("->" + ln.data);
			ln = ln.next;
		}
		System.out.println();
	}
}

双向循环链表

双向循环链表相对于双向链表,其尾节点的后继节点next不再指向null,而是指向头节点即尾节点的后继节点为头节点;其头节点的前驱节点不再指向null,而是指向尾节点,头节点的前驱节点为尾节点。

在这里插入图片描述
Java实现

相对于双向链表需要修改

1.添加第一个节点(add)

2.前插(insBefore),后插操作(insAfter)

3.删除操作(delBydata)

4.涉及变量链表的操作:查找target对应的节点(searchByData),链表是否包含节点(contains),打印链表(printLList)

public class DoubleCycleLinkedList {
	private DLNode first;
	private DLNode last;

	public DoubleCycleLinkedList() {
		first = null;
		last = null;
	}

	/**
	 * 1.增:添加第一个节点(头节点经过创建不在改变,修改尾节点)
	 */
	public DLNode addFirst(DLNode node) {
		first = node;
		last = node;
		node.next = node;
		node.prior = node;
		return node;
	}

	/**
	 * 1.增:前插入节点,循环链表的任何节点都有父节点,所以不需要做处理(单个节点的父节点是自身)
	 */
	public DLNode insBefore(int target, DLNode node) throws Exception {
		DLNode pre;
		DLNode cur;
		cur = this.searchByData(target);
		pre = cur.prior;
		// 插入节点
		node.next = first;
		first.prior = node;
		node.prior = pre;
		pre.next = node;
		// 如果cur是头节点,那么插入后需要更新尾节点
		if (cur == first) {
			last = node;
		}
		return node;
	}

	/**
	 * 1.增:后插入节点,循环链表的任何节点都有父节点,所以不需要做处理(单个节点的父节点是自身)
	 */
	public DLNode insAfter(int target, DLNode node) throws Exception {
		DLNode aft;
		DLNode cur;
		cur = this.searchByData(target);
		aft = cur.next;
		// 插入节点
		cur.next = node;
		node.prior = cur;
		node.next = aft;
		aft.prior = node;
		// 当在last节点后插入节点时需要更新last
		if (cur == last) {
			last = node;
		}
		return node;
	}

	/**
	 * 2.删,删除指定的节点,成功返回被删除的节点
	 */
	public DLNode delByData(int target) throws Exception {
		DLNode temp;
		if (!this.containsData(target)) {
			throw new Exception("该链表不包含此节点,无法删除!");
		}
		// 链表为空
		if (this.isEmpty()) {
			throw new Exception("链表为空,无法删除!");
		} else if (first == last) {
			// 链表只有一个元素的情况
			temp = first;
			first = null;
			last = null;
		} else {
			// 链表有两个和两个以上的节点
			DLNode cur = this.searchByData(target);
			temp = cur;
			DLNode pre = cur.prior;
			DLNode aft = cur.next;
			// 删除节点
			pre.next = aft;
			aft.prior = pre;
			// 删除的为头节点,更新头节点为下一个节点
			if (cur == first) {
				first = aft;
				// 删除的为尾节点,更新尾节点为前一个节点
			} else if (cur == last) {
				last = pre;
			}
		}
		return temp;
	}


	/**
	 * 4.查,由data值查找LNode的位置
	 */
	public DLNode searchByData(int target) throws Exception {
		DLNode temp = first;
		while (temp != null) {
			if (temp.data == target) {
				break;
			}
			temp = temp.next;
		}
		return temp;
	}

	/**
	 * 链表是否包含node
	 */
	public boolean containsData(int target) {
		boolean flag = false;
		DLNode dln = first;
		// 首先判断第一个元素是否为target
		if (first.data == target) {
			flag = true;
		} else {
			// 如果第一个元素不是target,从第二个元素开始遍历链表,循环条件改变为dln!=first
			while (dln != first) {
				if (dln.data == target) {
					flag = true;
					break;
				}
				dln = dln.next;
			}
		}
		return flag;
	}

	/**
	 * 打印链表
	 */
	public void printLList() {
		if (this.isEmpty()) {
			System.out.println("链表为空!");
			return;
		}
		DLNode ln = first;
		System.out.print(ln.data);
		ln = first.next;
		while (ln != first) {
			System.out.print("->" + ln.data);
			ln = ln.next;
		}
		System.out.println();
	}

---------------------------------------------------------------------------------------------------------------------------------------------参考资料:

数据结构 严蔚敏 吴伟民

​ https://www.jianshu.com/p/1cbd7e7414b7

​ https://www.jianshu.com/p/49f1f6c1cd3d

​ https://blog.csdn.net/LYR1994

​ https://blog.csdn.net/qq_25343557/article/details/83661240

​ https://blog.csdn.net/fanyun_01/article/details/79831877

​ https://blog.csdn.net/sinat_39061823/article/details/74935755

​ https://blog.csdn.net/wyqwilliam/article/details/82719058

​ https://blog.csdn.net/wangzhen209/article/details/8180462

( 注:部分资料参考网络,如有侵权或错误请在留言与我联系,欢迎关注我的微信公众号“搬砖小张”,一起学习,一起进步)

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬砖小张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值