(1)链表是以节点的方式来存储,是链式存储
(2)每个节点包含data域,next域:指向下一个节点
(3)链表的各个节点不一定是连续存储
(4)链表分为带头节点的链表和没有头节点的链表,根据实际的需求来确定
目录
1、使用带head头的单向链表实现,对水浒传人物的增删改查操作。
(1)添加元素,直接添加至链表尾部
添加(创建)
先创建一个head头节点,作用就是表示单链表的头(不存放具体的数据)
后面我们每添加一个节点,就直接加入到链表的最后
遍历
* 通过一个辅助变量遍历*
(2)添加元素,按照no顺序
首先找到新添加的节点的位置,是通过辅助变量(指针),通过遍历来搞定
新的节点.next=temp.next;
将 temp.next=新的节点
(3)修改节点
先找到节点,通过遍历
temp.name=newHerNode.name;
temp.nikname=newHerNode.nikname;
(4)删除节点
从单链表中删除一个节点的思路
先找到需要删除的这个节点的前一个节点temp
temp.next=temp.next.next;
被删除的节点,将不会有其他引用指向,会被垃圾回收机制回收
package database;
public class SingleLinkedListDemo {
public static void main(String[] args) {
HeroNode heroNode1= new HeroNode(1,"松江","及时雨");
HeroNode heroNode2= new HeroNode(2,"卢俊义","玉麒麟");
HeroNode heroNode3= new HeroNode(3,"吴勇","智多星");
SingleLinkedList s = new SingleLinkedList();
/* s.add(heroNode1);
s.add(heroNode3);
s.add(heroNode2);*/
//按顺序排序
s.addByOrder(heroNode1);
s.addByOrder(heroNode3);
s.addByOrder(heroNode2);
//列出数据
s.list();
System.out.println("---------------");
//更新数据
HeroNode newHeroNode =new HeroNode(2,"周瑜","黑旋风");
s.update(newHeroNode);
s.list();
//删除节点
System.out.println("---------------------------");
s.del(3);
s.list();
}
}
class SingleLinkedList{
private HeroNode head =new HeroNode(0,"","");
//返回头结点
public HeroNode gethead(){
return head;
}
//添加节点在链表尾部
public void add(HeroNode heroNode){
HeroNode temp=head;
//遍历链表
while (true){
if (temp.next==null){
break;
}
temp =temp.next;
}
temp.next=heroNode;
}
//添加英雄,按照顺序
public void addByOrder(HeroNode heroNode){
HeroNode temp=head;
boolean falg=false;
while (true){
if (temp.next==null){
// System.out.println("数组为空");
break;
}
if (temp.next.no> heroNode.no){
break;
}
if (temp.next.no==heroNode.no){
System.out.println("已经存在");
falg=true;
}
temp=temp.next;
}
if (falg){
System.out.println("数组已满");
}else {
heroNode.next=temp.next;
temp.next=heroNode;
}
}
//修改名字,昵称,根据no修改,且no不能改变
public void update(HeroNode newHeroNode){
if (head.next==null){
System.out.println("已到数组最后");
return;
}
HeroNode temp =head.next;
boolean flag=false;
while (true){
if (temp==null){
System.out.println("修改的数组为空");
break;
}
if (temp.no== newHeroNode.no){
//找到修改节点
flag=true;
break;
}
temp=temp.next;
}
if (flag){
temp.name=newHeroNode.name;
temp.nikname=newHeroNode.nikname;
}else {
//没找到修改的节点
System.out.println("未找到对应的节点");
}
}
//删除节点
public void del(int no){
HeroNode temp=head;
boolean flag=false;
while (true){
if (temp.next==null){
System.out.println("已经遍历完最后一个节点,删除节点为空");
break;
}
if (temp.next.no==no){
flag=true;
break;
}
temp=temp.next;
}
if (flag){
temp.next=temp.next.next;
}
}
//显示遍历
public void list(){
//判断是否为空
if (head.next==null){
System.out.println("链表为空");
return;
}
HeroNode temp=head.next;
while (true){
if (temp==null){
break;
}
System.out.println(temp);
temp=temp.next;
}
}
}
class HeroNode{
public int no;
public String name;
public String nikname;
public HeroNode next;
//构造器
public HeroNode(int no, String name, String nikname){
this.no=no;
this.name=name;
this.nikname=nikname;
}
@Override
public String toString() {
return "HeroNode{" +
"no=" + no +
", name='" + name + '\'' +
", nikname='" + nikname + '\'' +
'}';
}
}
单链表一些题
(1)求单链表中有效节点的个数
//单链表中获得有效节点个数(存放数据的节点) ,不包含头节点
//return 返回有效节点数
public static int getLength(HeroNode head) {
if (head == null) {
return 0;
}
int length = 0;
HeroNode cur = head.next;
while (cur != null) {
length++;
cur = cur.next; //遍历
}
return length;
}
(2)查找单链表中的倒数第k个结点 【新浪面试题】
//寻找单链表中的倒数第k个节点
public static HeroNode findlastindex(HeroNode head, int index) {
//判断链表是否为空
if (head.next == null) {
//有一个头节点的空链表
return null;
}
//第一遍遍历,得到数组长度
int size = getLength(head);
//第二遍遍历,对size-index 要求
if (index > size || index <= 0) {
return null;
}
//for循环遍历
HeroNode cur = head.next;
for (int i = 0; i < size - index; i++) {
cur = cur.next;
}
return cur;
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode getKthFromEnd(ListNode head, int k) {
if(head==null){
return null;
}
int n=0; //循环查看有多少个节点
ListNode curhead = head;
while(curhead!=null){
n++;
curhead=curhead.next;
}
int index=n-k;
if(index<0||k>n){
return null;
}
curhead=head;
for(int i=0;i<index;i++){
curhead=curhead.next;
}
return curhead;
}
}
(3)单链表的反转【腾讯面试题,有点难度】
//实现单链表反转
public static void reversedlist(HeroNode head){
if ((head.next==null)||(head.next.next==null)){
return;//为空链表或者为只有一个节点的链表
}
//定义一个辅助的指针
HeroNode cur =head.next;
HeroNode next =null;
HeroNode reversedhead =new HeroNode(0,"","");
//遍历链表herohead
while (cur!=null){
next =cur.next;
cur.next=reversedhead.next;
reversedhead.next=cur;
cur=next;
}
head.next=reversedhead.next;
}
(4)从尾到头打印单链表 【百度,要求方式1:反向遍历 。 方式2:Stack栈】
//用栈反转链表
public static void reversestack(HeroNode head){
if (head.next==null){
return;
}
Stack<HeroNode> stack = new Stack<HeroNode>();
HeroNode cur=head.next;
while (cur!=null){
stack.push(cur);
cur=cur.next;
}
while (stack.size()>0){
System.out.println( stack.pop());
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if (head==null){
return null;
}
Stack<ListNode> stack =new Stack<>();
ListNode cur=head;
while (cur!=null){
stack.push(cur);
cur=cur.next;
}
ListNode res= stack.pop();
ListNode node=res;
while (stack.size()>0){
node.next= stack.pop();
node=node.next;
}
node.next=null;
return res;
}
}
(5)合并两个有序的单链表,合并之后的链表依然有序【课后练习.】
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode lN=new ListNode(0);//指针不存放实际数据
ListNode cur=lN;
while (l1!=null&&l2!=null){
if (l1.val<l2.val){
cur.next=l1;
cur =cur.next;
l1=l1.next;
}else {
cur.next=l2;
cur=cur.next;
l2=l2.next;
}
}
if (l1==null){
cur.next= l2;
}else {
cur.next=l1;
}
return lN.next;
}
}