一、链表与顺序表区别
二、链表的结构
1、带头节点
2、不带头节点
三、实现一个带头节点的链表
方法:
1、增加(头插、尾插)
2、删除某个节点
3、输出链表
4、得到链表指定位置节点
5、逆置链表
6、得到链表长度
四、不带头结点链表
方法:
1、增加(头插、尾插)
2、删除某个节点
3、输出链表
4、得到链表指定位置节点
5、逆置链表
6、得到链表长度
7、查找链表倒数第k个节点
8、合并两个有序链表
9、逆序输出链表
10、不允许遍历链表,在 pos 前插入一个节点

一、链表与顺序表区别
顺序表:
底层实现是数组,是一段连续的内存空间;
遍历和查找元素比较容易,插入删除比较复杂;
数组的大小确定后,要更改需要花费较大的代价。

链表:
对于每一个链表来说,都有一个数据域和一个引用域,这个引用域是链表下一个节点的引用;
对于链表来说,插入删除元素容易,遍历链表相对顺序表来说困难;
同时,链表的物理位置不确定,可能是一段连续的内存空间、也可能不是一块连续的内存空间,由每个节点的引用域确定。

二、链表的结构
这里有一个技巧,也就是设计链表时用到的一个名叫头节点的东西–>head。
在带头节点的链表中,头节点的意义是:在单链表的第一个结点之前附设的一个结点
不带头节点的链表中,头节点仅仅只是标记着链表中第一个元素的位置。
1、带头节点

2、不带头节点

三、实现一个带头节点的链表

class linkedListWithHead<T> {// head 是指向链表中第一个节点的引用protected Node<T> head;class Node<E> {protected E element;//数据域protected Node<E> next;//引用域public Node(E element) {this.element = element;}}//为 head 开辟空间public linkedListWithHead() {head = new Node<>((T) new Object());}//头插public void addHead(T data) {//创建一个新节点Node<T> newNode = new Node<>(data);//绑定新节点newNode.next = head.next;head.next = newNode;}//尾插public void addTail(T data) {//创建一个新节点Node<T> newNode = new Node<>(data);Node<T> temp = head;//先遍历,找到最后一个节点while (temp.next != null) {temp = temp.next;}//绑定新节点temp.next = newNode;}//输出链表  重写 toString()方法public String toString() {StringBuilder sbr = new StringBuilder();Node<T> temp = head;while (temp.next != null) {sbr.append(temp.next.element + " ");temp = temp.next;}return sbr.toString();}//删除某个值public boolean delete(T data) {if (head.next == null) return false;//判断头节点是不是要被删除的元素if (head.element == data) {head = head.next;return true;}Node<T> temp = head;//在普通节点里面寻找要被删除的元素while (temp.next != null) {if (temp.next.element == data) {temp.next = temp.next.next;return true;}temp = temp.next;}return false;}//逆置链表  以头插的方式完成/*用 temp 指向链表中第一个数的引用,从第一个数开始挪temp = head.next;   head.next = null;将 temp 的后面的数即链表中第二个数先保存 tempNext = temp.next此时链表分为头节点、链表中第一个数、第二个数及其后的数此时 temp 已经孤立,可以对其操作把 temp 以头插的方式插入到链表中以此类推...*/public void reverseMineLikeInsertHead() {//空链表则返回if (head.next == null) return;Node<T> temp = head.next;head.next = null;while (temp != null) {Node<T> tempNext = temp.next;temp.next = head.next;head.next = temp;temp = tempNext;}}//得到指定位置的节点元素  下标:0 1 2 3 4public T getIndexValue(int index) {//链表为空则返回if (head.next == null || index < 0) return null;Node<T> temp = head;while (temp.next != null && index-- > 0) {temp = temp.next;}if (index <= 0) {return temp.next.element;}//下标:0, 1, 2, 3return null;//return temp.element, 下标:1, 2, 3, 4}//得到链表长度public int getLength() {//链表为空则返回if (head.next == null) return -1;int size = 0;Node<T> temp = head;while (temp.next != null) {size++;temp = temp.next;}return size;}
}

四、不带头结点链表

class LinkedListWithoutHead<T extends Comparable<T>> {class Node<E> {public E element;public Node<E> next;public Node(E data) {this.element = data;}}//head 标记着链表的第一个元素public Node<T> head;public LinkedListWithoutHead() {head = null;}//头插public void addHead(T data) {//第一次创建的时候,newNode 是第一个节点, head是链表中第一个节点的标记//第二次Node<T> newNode = new Node<>(data);//当前链表中已有节点,让 head 只作为链表中第一个元素的标记if (head != null) {//此时 newNode 是第二个节点,它的 next 域是链表中第一个节点,这个节点用 head 标记newNode.next = head;//把 head 的引用赋给第二个节点的 next 域//以此类推...}//当前链表中没有节点,让 head 做标记//已有,更新 headhead = newNode;}//尾插public void addTail(T data) {Node<T> newNode = new Node<>(data);//仍然判断链表是否为空if (head != null) {//head 是链表中第一个元素的标记,不能随便搞Node<T> temp = head;//遍历链表,找到链表中最后一个元素while (temp.next != null) {temp = temp.next;}temp.next = newNode;//有 return 语句不用 else 语句
//            return;} else {//链表为空,让 head 做链表第一个元素的标记head = newNode;}}//删除public boolean delete(T value) {if (head == null) return false;if (value == head.element) {head = head.next;return true;}Node<T> temp = head;while (temp.next != null) {if (value == temp.next.element) {temp.next = temp.next.next;}temp = temp.next;}return false;}//在指定位置添加一个节点public boolean addInGivenPosition(T data, int pos) {if (pos < 0 || pos > getLength() + 1 || head == null) return false;Node<T> newNode = new Node<>(data);if (pos == 0) {newNode.next = head;head = newNode;return true;}Node<T> temp = head;//大于 1 可以添加在指定下标while (temp.next != null && pos-- > 1) {temp = temp.next;}Node<T> tempNode = temp.next;temp.next = newNode;newNode.next = tempNode;return true;}//以头插的方式逆置链表public void reverseLikeInsertHead() {//链表为空或只有一个节点,不用逆置if (head == null || head.next == null) return;if (head.next != null) {Node<T> temp = head.next;head.next = null;while (temp != null) {Node<T> tempNext = temp.next;temp.next = head;head = temp;temp = tempNext;}}}//打印链表   toStringpublic String toString() {StringBuilder sbr = new StringBuilder();//此时head 指向链表中第一个元素Node<T> temp = head;while (temp != null) {sbr.append(temp.element + " ");temp = temp.next;}return sbr.toString();}//打印链表  循环public void showLink() {Node<T> temp = head;while (temp != null) {System.out.print(temp.element + " ");temp = temp.next;}System.out.println();}//链表长度public int getLength() {int size = 0;Node<T> temp = head;while (temp != null) {size++;temp = temp.next;}return size;}//返回指定节点public T getIndexValue(int index) {if (head == null || index < 0) return null;Node<T> temp = head;while (temp != null && index-- > 0) {temp = temp.next;}if (index <= 0) {return temp.element;}return null;}//返回链表的头public Node<T> getHead() {return head;}//设置链表的头public void setHead(Node<T> head) {this.head = head;}//合并两个有序列表public Node<T> mergeMyLink(Node<T> head1, Node<T> head2) {if (head1 == null) return head2;if (head2 == null) return head1;Node<T> curHead;if (head1.element.compareTo(head2.element) < 0) {curHead = head1;head1 = head1.next;} else {curHead = head2;head2 = head2.next;}Node<T> temp = curHead;while (head1 != null && head2 != null) {if (head1.element.compareTo(head2.element) <= 0) {temp.next = head1;head1 = head1.next;temp = temp.next;} else {temp.next = head2;head2 = head2.next;temp = temp.next;}}if (head1 == null) {temp.next = head2;} else if (head2 == null) {temp.next = head1;}head = curHead;return head;}//逆序输出单链表public  <T> void reversePrintList(Node<T> head){//递归终止条件if(head == null){return;//处理办法}//提取重复逻辑,缩小问题规模reversePrintList(head.next);System.out.print(head.element + " ");}//查找单链表中倒数第K个元素public T findReverseValue(LinkedListWithoutHead<T> list,int k){if (k <= 0 || k > list.getLength()) return null;//倒数第 k 个不就是 list.getLength() - k int index = list.getLength() - k;Node<T> temp = head;while (temp != null && index-- >0){temp = temp.next;}if (index <= 0){return temp.element;}return null;}//查找链表倒数第k个元素  高效算法public Node<T> findElem(Node<T> head, int k) {if(k < 1 || head == null) {return null;}Node<T> front = head;Node<T> behind = head;/*搞一个快引用,一个慢引用让快引用先走它个 k-1 米当它还可以继续给后走快、慢一起做运动当快引用走到最后一个时慢引用恰好走到倒数第 k 个努力运动、好好 keep 哦*/for(int i=0; i<k-1; i++){if(front.next != null){front = front.next;}else{return null;}}while(front.next != null){front = front.next;behind = behind.next;}return behind;}//不允许遍历链表,在 pos 前插入 data/*先把新节点放到 pos 后,把 pos.element 赋值给新的节点再把 data 赋值给 pos.element偷天换日,假装插到了 pos 前*/public void NoCycleInsertBeforePos(LinkedListWithoutHead<T> list, Node<T> pos, T data){if (list.head == null || pos == null) return;Node<T> newNode = new Node<>(data);newNode.next = pos.next;pos.next = newNode;newNode.element = pos.element;pos.element = data;}}

带头与不带头节点单链表相关推荐

  1. 带头节点单链表的增删改查

    单链表有很多结构循环单链表,有头节点的单链表,无头节点的单链表,双节点单链表,以下源码是以有一个头节点的单链表为例写的增删改查的各种功能,就是下图 然后各个注释也在函数后面写着,这玩意确实还挺难,源码 ...

  2. 带表头节点单链表及其基本应用

    带表头节点单链表及其基本应用 结构体及其宏定义和所需要的C语言库 #include <stdio.h> #include <stdlib.h> #define ERROR 0 ...

  3. c语言带头节点单链表创建,C语言建立带头结点的单链表

    满意答案 TS老妹儿 2017.08.31 采纳率:57%    等级:9 已帮助:1719人 单链表的生成有2种方式:头插法和尾插法. 1.头插法/************************* ...

  4. 不带头结点的C语言单链表操作,头插法及尾插法

    接上篇带头结点的单链表操作,不带头节点真的比带头结点的麻烦好多,主要是我自己指针指的有点晕,搞了这几天的不带头结点的单链表,算是弄清楚指针的玩法了..老样子上代码. # include "s ...

  5. 对(不带头单向不循环)单链表的初步认识

    <一>:什么是单链表及其结构 <二>:如何实现单链表 <三>:单链表与顺序表的区别 <一>:什么是单链表及其结构: 1.概念:单链表是一种物理存储结构上 ...

  6. 带有头节点单链表,带有头节点单链表逆置的四种方法

    文章目录 带头结点的单链表 单链表逆置的四种做法 带头结点的单链表 链式存储结构:逻辑上相邻的数据元素,并不要求物理上也相邻: 单链表的代码实现 .h文件 #pragma once typedef i ...

  7. C语言——带头节点单链表常见操作

    #include <stdio.h> #include <stdlib.h> typedef struct stu {int data; //存放数据struct stu* n ...

  8. 数据结构-带头节点的单链表(C语言)超详细讲解

    前面我们学到线性表的顺序存储结构(顺序表),发现它有着明显的缺点:插入和删除元素时需要频繁的移动元素,运算效率低.必须按事先估计的最大元素个数申请连续的存储空间.存储空间估计大了,造成浪费空间:估计小 ...

  9. 删除带头结点的单链表的奇数结点

    [单链表算法]设带头结点的非空单链表 L,设计一个算法删除 L 中奇数序号 的结点,即删除 L 中第 1.3.5-结点. #include<stdio.h> #include<mal ...

最新文章

  1. 在软件中常用的“撤销”操作,其本质是“栈”!
  2. 推荐一本好书《改变,从阅读开始》
  3. 用 Go 构建一个区块链 -- Part 3: 持久化和命令行接口
  4. 16福师计算机应用基础在线作业,16春季福师《计算机应用基础》在线作业二.doc...
  5. byte[]、sbyte[]、int[]以及Array的故事
  6. hive能替代oracle_Hive与Oracle表关联语句对比
  7. Python+OpenGL实现物体快速运动时的模糊效果
  8. 利用rman配置DG环境
  9. noip2016 蚯蚓
  10. labelme安装及标签制作
  11. 离线电商数仓3.0项目即席查询复盘笔记
  12. 计算机辅助设计和工程图学,工程制图与计算机辅助设计
  13. 关于微信小程序web开发者工具模拟器出现空白问题
  14. MySQL复制表数据到新表的方法
  15. python大数据之缺省值处理
  16. 说话人识别(声纹识别)综述
  17. 汽车制动盘的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  18. 精英反向学习与黄金正弦优化的HHO算法
  19. 苦瓜炒鸡蛋怎么做 夏日降火家常菜
  20. div中内容水平垂直居中

热门文章

  1. 基于51单片机的超声波倒车雷达防撞系统 原理图程序设计 数码管显示
  2. PHP 递归寻找上下级DEMO
  3. python函数的作用是什么_Python函数
  4. Android 系统应用开发-模拟器调试
  5. iOS马甲包修改说明
  6. 分布式事务管理Atomikos
  7. 创建火箭弹-2020-09-10
  8. 射频测试 —— 蓝牙定频测试2
  9. 如何绕过大写过滤器实现XSS攻击
  10. 最简单的微信视频号下载方法,收藏备用超级实用