【算法day6】哈希表、有序表、链表(反转单链表)

哈希表的简单介绍

1)哈希表在使用层面上可以理解为一种集合结构

2)如果只有key,没有伴随数据value,可以使用HashSet结构(C++中叫UnOrderedSet)

3)如果既有key,又有伴随数据value,可以使用HashMap结构(C++中叫UnOrderedMap)

4)有无伴随数据,是HashMap和HashSet唯一的区别,底层的实际结构是一回事

5)使用哈希表增(put)、删(remove)、改(put)和查(get)的操作,可以认为时间复杂度为O(1)(常数级别),但是常数时间比较大

6)放入哈希表的东西,如果是基础类型,内部按值传递,内存占用就是这个东西的大小

7)放入哈希表的东西,如果不是基础类型,内部按引用传递,内存占用是这个东西内存地址的大小

有序表的简单介绍

1)有序表在使用层面上可以理解为一种集合结构

2)如果只有key,没有伴随数据value,可以使用TreeSet结构(C++中叫OrderedSet)

3)如果既有key,又有伴随数据value,可以使用TreeMap结构(C++中叫OrderedMap)

4)有无伴随数据,是TreeSet和TreeMap唯一的区别,底层的实际结构是一回事

5)有序表和哈希表的区别是,有序表把key按照顺序组织起来,而哈希表完全不组织

6)红黑树AVL树size-balance-tree跳表等都属于有序表结构,只是底层具体实现不同

7)放入有序表的东西,如果是基础类型,内部按值传递,内存占用就是这个东西的大小

8)放入有序表的东西,如果不是基础类型,必须提供比较器,内部按引用传递,内存占用是这个东西内存地址的大小

9)不管是什么底层具体实现,只要是有序表,都有以下固定的基本功能和固定的时间复杂度

有序表的固定操作

void put(K key,V value):将一个(key,value)记录加入到表中,或者将key的记录更新成value。

v get(k key):根据给定的key,查询value并返回。3) void remove(K key):移除key的记录。

boolean containsKey(K key):询问是否有关于key的记录。

K firstKey():返回所有键值的排序结果中,最左(最小)的那个。6)K lastKey():返回所有键值的排序结果中,最右(最大)的那个。

K floorKey (K key):如果表中存入过key,返回key;否则返回所有键值的排序结果中,,,key的前一个。

K ceilingKey (K key):如果表中存入过key,返回key;否则返回所有键值的排序结果中,key的后一个。

以上所有操作时间复杂度都是0(logN),N为有序表含有的记录数

链表

链表知识学习:https://blog.csdn.net/m0_57950108/article/details/121639962

java知识回忆:https://www.liaoxuefeng.com/wiki/1252599548343744/1260454185794944

单向链表反转

假设有以下链表

1→2→3→null

需要返回的链表是

3→2→1→null

怎么做?

一般有两种做法

方法一:使用一个中间变量保存下一节点指针

视频讲解:https://www.bilibili.com/video/BV1KZ4y157Up/?spm_id_from=333.788

单链表的每个节点都只存了它的下一节点的地址指针

因此,设三个变量

pre:代表指向当前节点上一个节点的指针

cur:代表指向当前节点的指针

tmp:用于保存指向当前节点下一个节点的指针

public class LinkNode ReverseList {
	# 定义一个单链表
	public static class Node {
		public int value; //节点储存的值
		public Node next; //节点储存的下一节点的地址指针

		public Node(int data) {
			this.value = data;
		}
	}
	# 创建一个单链表反转方法
	public static Node reverseList(Node head) {
		Node pre = null; //指向当前节点的前一个节点的指针
        Node cur = head; //指向当前节点的指针
		Node tmp; //用于保存当前节点的下一节点,防止链表断掉
		while (cur != null) {
            //先将当前节点的后一个节点的地址保存
			tmp = cur.next;
            //将当前节点的后一个节点指针指向当前节点的前一个节点
			cur.next = pre;
            //将pre指向当前节点位置
			pre = cur;
            //将当前节点位置后移
            //此时已经是2-1-3了
			cur = tmp;
		}
        //等pre指到链表尾部(null)时结束并返回前一个值
        //此时链表变为3-2-1
		return pre;
	}
    
    public static void printLinkedList(Node head) {
		System.out.print("Linked List: ");
		while (head != null) {
			System.out.print(head.value + " ");
			head = head.next;
		}
		System.out.println();
	}
    
    public static void main(String[] args) {
		Node head1 = new Node(1);
		head1.next = new Node(2);
		head1.next.next = new Node(3);
		printLinkedList(head1);
		head1 = reverseList(head1);
		printLinkedList(head1);
	}

} 

方法二:不使用中间变量(via左神)

public class LinkNode ReverseList {
	# 定义一个单链表
	public static class Node {
		public int value; //节点储存的值
		public Node next; //节点储存的下一节点的地址指针

		public Node(int data) {
			this.value = data;
		}
	}
	# 创建一个单链表反转方法
	public static Node reverseList(Node head) {
		Node pre = null; //指向当前节点的前一个节点的指针
        Node next = null; //指向当前节点的后一个节点的指针
      //若头结点不为空
		while (head != null) {
            //先将头结点的后一个节点的地址保存
			next = head.next;
            //将头结点的后一个节点指针指向头结点的前一个节点
			head.next = pre;
            //将pre指向当前节点(头结点)位置
			pre = head;
            //将当前节点位置后移,移动到下一个数
            //此时已经是2-1-3了
			head = next;
		}
        //等pre指到链表尾部(null)时结束并返回前一个值
        //此时链表变为3-2-1
		return pre;
	}
    
    public static void printLinkedList(Node head) {
		System.out.print("Linked List: ");
		while (head != null) {
			System.out.print(head.value + " ");
			head = head.next;
		}
		System.out.println();
	}
    
    public static void main(String[] args) {
		Node head1 = new Node(1);
		head1.next = new Node(2);
		head1.next.next = new Node(3);
		printLinkedList(head1);
		head1 = reverseList(head1);
		printLinkedList(head1);
	}

}
posted @ 2022-05-11 19:53  dayceng  阅读(122)  评论(0编辑  收藏  举报