java数据结构以及算法

java数据结构以及算法

字符串A 字符串B。判断B串是否存在于A串中。
KMp 部分匹配表

分治算法
回溯算法

一、 数据的结构(data structure)

特点:
研究组织数据方式
程序 =数据结构 +数据算法

修路问题? 最小生成树【数据结构】+ 普利姆算法
虽短路径? 图+弗洛伊德算法
汉诺塔? 分支算法
八皇后问题? 回溯算法

字符串替换问题?需要单链表数据结构

五子棋程序? 二维数组+稀疏数组
丢手帕? 单向环形链表

二、数据结构包括 :线性结构 非线性结构

(1)线性结构:数组,链表,队列,栈

数据元素之间一对一
线性结构有两种存储方式: 顺序存储 地址连续链式存储–>可以很好的利用内存碎片

(2)非线性结构:二维数组,多维数组,广义表,树结构,图结构

1,稀疏数组
当一个数组大多数的元素为0,可以使用稀疏数组存储

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

二维数组 转 稀疏数组的思路
1. 遍历  原始的二维数组,得到有效数据的个数 sum
2. 根据sum 就可以创建 稀疏数组 sparseArr   int[sum + 1] [3]
3. 将二维数组的有效数据数据存入到 稀疏数组

稀疏数组转原始的二维数组的思路

1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的  chessArr2 = int [11][11]
2. 在读取稀疏数组后几行的数据,并赋给 原始的二维数组 即可.

代码示例

package xishu_arry;

import java.io.*;

public class SparseArray {

    public static void main(String[] args) throws IOException {
        //1----------------初始化创建11*11的二维数组--------------------
        //0代表没有子 1黑子,2代表白子

        int  chessArr1[][] = new int[11][11];
        //赋值
        chessArr1[1][2]=1;
        chessArr1[2][3]=2;

        for (int[] ints : chessArr1) {
            for (int anInt : ints) {
                System.out.print(anInt+"\t");
            }
            System.out.println();
        }

        //---------------------将二维数组 转化为稀疏数组------------------
        //1.-----遍历二维数组 得到非零数据个数----

        //获取原始数组的行数 chessArr1.length,和列数 chessArr1[0].length
        int sum = 0;
        for (int i = 0; i < chessArr1.length; i++) {
           for (int j=0;j<chessArr1[0].length;j++){
               if (chessArr1[i][j] !=0){
                   sum++;
               }
           }
        }
        System.out.println("有效数据个数:"+sum);

        //创建稀疏数组

        int sparseArr[][] = new int[sum+1][3];
        //给稀疏数组赋值
        //给第一行数据赋值依次是 原数组行, 原数组列 ,元素组存储的数据个数
        sparseArr[0][0]=chessArr1.length;//原数组行
        sparseArr[0][1]=chessArr1[0].length;//原数组列
        sparseArr[0][2]=sum;//元素组存储的数据个数

        int count = 0;//记录不为o的数值的行数
        for (int i = 0; i < chessArr1.length; i++) {
            for (int j=0;j<chessArr1[0].length;j++){

                //存储非零值
                if (chessArr1[i][j] !=0){

                    count++;//最小从1开始。应为0行被占用了。
                    sparseArr[count][0]=i;//行
                    sparseArr[count][1]=j;//列
                    sparseArr[count][2]=chessArr1[i][j];//值
                }
            }
        }

        System.out.println("稀疏数组------>");
        for (int i = 0; i < sparseArr.length; i++) {
            for (int j=0;j<sparseArr[0].length;j++){
                System.out.print(sparseArr[i][j]+"\t");
            }
            System.out.println();
        }


        //3.--------------将稀疏数组恢复至原始数组---------------
        int hange =sparseArr[0][0];
        int lie =sparseArr[0][1];

        //将数据赋值给棋子数组
      chessArr1 =new int[hange][lie];
        for (int i = 1; i < sparseArr.length; i++) {//表示行
            chessArr1[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];//值的元素
        }
        //做遍历
        //数据写入文件
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "GBK");
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);

        StringBuffer stringBuffer = new StringBuffer();
        for (int[] ints : chessArr1) {
            for (int anInt : ints) {

                stringBuffer.append(anInt);
                System.out.print(anInt+"\t");
            }
            bufferedWriter.write(stringBuffer.toString());
            bufferedWriter.newLine();
            stringBuffer.delete(0,chessArr1.length);//清除了。

            System.out.println();
        }






            bufferedWriter.close();









        //----------------------------------------

        //从文件中读取数据

        FileInputStream inputStream = new FileInputStream("D:\\a.txt");
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);

        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        while (true){
            String s = bufferedReader.readLine();
            if (s==null)break;
            System.out.println(s);
        }


    }



}


java 的io存储,读取

 //做遍历
        //数据写入文件
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "GBK");
        PrintWriter printWriter = new PrintWriter(outputStreamWriter);




        for (int[] ints : chessArr1) {
            for (int anInt : ints) {
                printWriter.write(String.valueOf(anInt));
                System.out.print(anInt+"\t");
            }
            System.out.println();
        }
        printWriter.close();




        //----------------------------------------

        //从文件中读取数据

        FileInputStream inputStream = new FileInputStream("D:\\a.txt");
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);

        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        while (true){
            String s = bufferedReader.readLine();
            if (s==null)break;
            System.out.println(s);
        }

三、队列

案例:
在这里插入图片描述
代码实现。但是存在问题,用过的数组空间不能再次使用
在这里插入图片描述

package queue;

import java.util.Scanner;

public class MyQueue {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        char key = ' '; //接收用户输入
        Scanner scanner = new Scanner(System.in);

        boolean loop = true;

        //输出菜单
        while (loop){   //while true死循环
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加队列");
            System.out.println("g(get):从队列中获取数据");
            System.out.println("h(head):查看队列的头数据");
            key = scanner.next().charAt(0);//接收一字符
            switch (key){
                case 's':
                    arrayQueue.showQueue();//调用显示队列的方法
                    break;
                case 'e':
                    scanner.close();
                    loop =false;
                    break;
                case 'a':
                    System.out.println("请输入一个数字");
                    int value = scanner.nextInt();
                    arrayQueue.addQueue(value);//添加队列
                    break;
                case 'g':

                    try {
                        int queueElement = arrayQueue.getQueueElement();//取数据
                        System.out.println("取出的数据是%d\n:"+queueElement);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;

                case 'h':
                    try {
                        int i = arrayQueue.headQueue();//查看队列头数据
                        System.out.println("队列的头信息%d\n:"+i);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    break;

            }

        }
        System.out.println("程序退出.......");

    }
}

//数组模拟队列
class ArrayQueue{
    private int maxSize;//表示数组的最大长度
    private int front;//队列的头
    private int rear;//队列的尾部
    private int[] arr;//存数据的数组

    //创建队列的构造器。 初始化长度;
    public  ArrayQueue (int arrMaxSize){
        maxSize=arrMaxSize;
        arr=new int[maxSize];
        front=-1;//指向队列头的前一个位置
        rear=-1;//指向队列尾部最后一个数据
    }

    //判断队列是否已满
    public boolean isFull(){
        return rear==maxSize-1;
    }
    //判断队列为空
    public boolean isEmpty(){
        return rear==front;//头指针==尾部指针
    }

    //添加队列

    public void addQueue(int n){
        //判断队列是否满
        if (isFull()){
            System.out.println("队列满,无法添加数据");
            return;
        }
        rear++;//让尾部指针后移
        arr[rear] = n;
    }

    //获取队列的数据。出队列
    public int getQueueElement(){
        //判断队列是否为空
        if (isEmpty()){
            //通过抛2异常处理
            throw new RuntimeException("队列为空,不能取数据!");
        }

        //不为空
        front++;//头指针后移
        return  arr[front];
    }

    //显示队列的所有数据

    public void showQueue (){
        //遍历
        if (isEmpty()){
            System.out.println("队列空,不能遍历");
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]+"\t");
        }

    }

    //显示队列的头数据
    public int headQueue(){
        //数据是否为空
        if (isEmpty()){
            throw  new RuntimeException("队列为空,没有数据");
        }
        return arr[front+1];

    }


}

环形数组

思路如下:
1.  front 变量的含义做一个调整: front 就指向队列的第一个元素, 也就是说 arr[front] 就是队列的第一个元素 
front 的初始值 = 0
2.  rear 变量的含义做一个调整:rear 指向队列的最后一个元素的后一个位置. 因为希望空出一个空间做为约定.
rear 的初始值 = 0
3. 当队列满时,条件是  (rear  + 1) % maxSize == front 【满】 (rear+1表示预留1个空间)
4. 对队列为空的条件, rear == front 空
5. 当我们这样分析, 队列中有效的数据的个数   (rear + maxSize - front) % maxSize   // rear = 1 front = 0 
6. 我们就可以在原来的队列上修改得到,一个环形队列

在这里插入图片描述

package queue.huan_xing_arr;

import java.util.Scanner;

public class MyCircleQueue {
    public static void main(String[] args) {
        CircleQueue circleQueue = new CircleQueue(3);
        char key = ' '; //接收用户输入
        Scanner scanner = new Scanner(System.in);

        boolean loop = true;

        //输出菜单
        while (loop){   //while true死循环
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加队列");
            System.out.println("g(get):从队列中获取数据");
            System.out.println("h(head):查看队列的头数据");
            key = scanner.next().charAt(0);//接收一字符
            switch (key){
                case 's':
                    circleQueue.showQueue();//调用显示队列的方法
                    break;
                case 'e':
                    scanner.close();
                    loop =false;
                    break;
                case 'a':
                    System.out.println("请输入一个数字");
                    int value = scanner.nextInt();
                    circleQueue.addQueue(value);//添加队列
                    break;
                case 'g':

                    try {
                        int queueElement = circleQueue.getQueueElement();//取数据
                        System.out.println("取出的数据是%d\n:"+queueElement);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;

                case 'h':
                    try {
                        int i = circleQueue.headQueue();//查看队列头数据
                        System.out.println("队列的头信息%d\n:"+i);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                default:
                    break;

            }

        }
        System.out.println("程序退出.......");

    }
}

//数组模拟队列
class CircleQueue{
    private int maxSize;//表示数组的最大长度
    private int front;//队列的头,指向队列第一个元素
    private int rear;//队列的尾部 指向最后元素的下一个位置
    private int[] arr;//存数据的数组

    //创建队列的构造器。 初始化长度;
    public  CircleQueue (int arrMaxSize){
        maxSize=arrMaxSize;
        arr=new int[maxSize];
        front=0;//指向队列头的前一个位置
        rear=0;//指向队列尾部最后一个数据
    }

    //判断队列是否已满
    public boolean isFull(){
        return  (rear+1)%maxSize ==front;
    }
    //判断队列为空
    public boolean isEmpty(){
        return rear==front;//头指针==尾部指针
    }

    //添加队列

    public void addQueue(int n){
        //判断队列是否满
        if (isFull()){
            System.out.println("队列满,无法添加数据");
            return;
        }
        //直接让数据加入
        arr[rear] = n;
        //将rear后移,必须考虑取模
        rear = (rear+1)%maxSize;
    }

    //获取队列的数据。出队列
    public int getQueueElement(){
        //判断队列是否为空
        if (isEmpty()){
            //通过抛2异常处理
            throw new RuntimeException("队列为空,不能取数据!");
        }

        //分析出front指向队列的第一个元素
        //1.先把front保存到一个临时变量
        //2.将front后移,考虑取2模
        //3.将临时变量返回
        int value = arr[front];//1
        front =(front+1)%maxSize;//2
        return value;

    }

    //显示队列的所有数据

    public void showQueue (){
        //遍历
        if (isEmpty()){
            System.out.println("队列空,不能遍历");
            return;
        }
        //有可能前面的数据已被取
        //存front开始取, 遍历多少元素?
        for (int i = front; i < front+sivesize(); i++) {
            System.out.println("下标:"+i%maxSize+"\t"+arr[i%maxSize]);
        }

    }

    //求出当前数组有效数据个数
    public int sivesize(){
        return (rear+maxSize-front )%maxSize;
    }

    //显示队列的头数据
    public int headQueue(){
        //数据是否为空
        if (isEmpty()){
            throw  new RuntimeException("队列为空,没有数据");
        }
        return arr[front];

    }


}

四、链表

特点;
(1) 链表用节点来存储
(2)每个节点包括data域,next域
(3)链表的节点不一定是连续的
(4)链表分带头节点,不带头的节点
在这里插入图片描述
单链表创建示意图

在这里插入图片描述

package lian_biao;

public class singleLinkedList {
    public static void main(String[] args) {

        //测试
        HeroNode heroNode1 = new HeroNode(1, "松江", "及时雨");
        HeroNode heroNode2 = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode heroNode3 = new HeroNode(3, "吴用", "智多星");
        HeroNode heroNode4 = new HeroNode(4, "林冲", "豹子头");

        SingleLinked singleLinked = new SingleLinked();
        singleLinked.add(heroNode1);
        singleLinked.add(heroNode2);
        singleLinked.add(heroNode3);
        singleLinked.add(heroNode4);
        //显示
        singleLinked.list();



    }
}
//-------------管理我们的英雄人物

class SingleLinked{
    //初始化一个头节点。头结点不要动,变化了找不到头
    private HeroNode head = new HeroNode(0,"","");
    //添加节点到单链表
    //思路:当不考虑编号顺序时
    //1.找到当前链表的最后一个节点
    //2.将最后这个节点的next指向新节点
    public void add(HeroNode heroNode){
        //因为head节点不能动,我们需要夜歌辅助遍历temp
        HeroNode temp = head;
        //遍历链表,找到最后
        while (true){
            if (temp.next==null){
                break;
            }
            //如果没到最后,将temp后移
            temp = temp.next;

        }
        //当while退出的时候,temp指向链表的最后
        temp.next = heroNode;//将添加的节点赋值给temp的下一个位置

    }

    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);
            //将next后移
            temp = temp.next;
        }
    }
}



class  HeroNode{
    public  int no;//英雄编号
    public String name;//英雄名字
    public String nickName;//昵称
    public HeroNode next ;//指向下一个节点

    public HeroNode(int no, String name, String nickName) {
        this.no = no;
        this.name = name;
        this.nickName = nickName;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickName='" + nickName + '\'' +
                ", next=" + next +
                '}';
    }
}

结果:

HeroNode{no=1, name='松江', nickName='及时雨', next=HeroNode{no=2, name='卢俊义', nickName='玉麒麟', next=HeroNode{no=3, name='吴用', nickName='智多星', next=HeroNode{no=4, name='林冲', nickName='豹子头', next=null}}}}
HeroNode{no=2, name='卢俊义', nickName='玉麒麟', next=HeroNode{no=3, name='吴用', nickName='智多星', next=HeroNode{no=4, name='林冲', nickName='豹子头', next=null}}}
HeroNode{no=3, name='吴用', nickName='智多星', next=HeroNode{no=4, name='林冲', nickName='豹子头', next=null}}
HeroNode{no=4, name='林冲', nickName='豹子头', next=null}

package com.atguigu.linkedlist;

import java.util.Stack;

public class SingleLinkedListDemo {

	public static void main(String[] args) {
		//进行测试
		//先创建节点
		HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
		HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
		HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
		HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
		
		//创建要给链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		
		
		//加入
		singleLinkedList.add(hero1);
		singleLinkedList.add(hero4);
		singleLinkedList.add(hero2);
		singleLinkedList.add(hero3);

		// 测试一下单链表的反转功能
		System.out.println("原来链表的情况~~");
		singleLinkedList.list();
		
//		System.out.println("反转单链表~~");
//		reversetList(singleLinkedList.getHead());
//		singleLinkedList.list();
		
		System.out.println("测试逆序打印单链表, 没有改变链表的结构~~");
		reversePrint(singleLinkedList.getHead());
		
/*		
		//加入按照编号的顺序
		singleLinkedList.addByOrder(hero1);
		singleLinkedList.addByOrder(hero4);
		singleLinkedList.addByOrder(hero2);
		singleLinkedList.addByOrder(hero3);
		
		//显示一把
		singleLinkedList.list();
		
		//测试修改节点的代码
		HeroNode newHeroNode = new HeroNode(2, "小卢", "玉麒麟~~");
		singleLinkedList.update(newHeroNode);
		
		System.out.println("修改后的链表情况~~");
		singleLinkedList.list();
		
		//删除一个节点
		singleLinkedList.del(1);
		singleLinkedList.del(4);
		System.out.println("删除后的链表情况~~");
		singleLinkedList.list();
		
		//测试一下 求单链表中有效节点的个数
		System.out.println("有效的节点个数=" + getLength(singleLinkedList.getHead()));//2
		
		//测试一下看看是否得到了倒数第K个节点
		HeroNode res = findLastIndexNode(singleLinkedList.getHead(), 3);
		System.out.println("res=" + res);
*/		
		
	}
	
	//方式2:
	//可以利用栈这个数据结构,将各个节点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果
	public static void reversePrint(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; //cur后移,这样就可以压入下一个节点
		}
		//将栈中的节点进行打印,pop 出栈
		while (stack.size() > 0) {
			System.out.println(stack.pop()); //stack的特点是先进后出
		}
	}
	
----------------------------3.------------------将单链表反转------------

	public static void reversetList(HeroNode head) {
		//如果当前链表为空,或者只有一个节点,无需反转,直接返回
		if(head.next == null || head.next.next == null) {
			return ;
		}
		
		//定义一个辅助的指针(变量),帮助我们遍历原来的链表
		HeroNode cur = head.next;
		HeroNode next = null;// 指向当前节点[cur]的下一个节点
		HeroNode reverseHead = new HeroNode(0, "", "");
		//遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead 的最前端
		//动脑筋
		while(cur != null) { 
			next = cur.next;//先暂时保存当前节点的下一个节点,因为后面需要使用
			cur.next = reverseHead.next;//将cur的下一个节点指向新的链表的最前端
			reverseHead.next = cur; //将cur 连接到新的链表上
			cur =   ;//让cur后移
		}
		//将head.next 指向 reverseHead.next , 实现单链表的反转
		head.next = reverseHead.next;
	}
------------------------------------------------------------------------------	
	//查找单链表中的倒数第k个结点 【新浪面试题】
	//思路
	//1. 编写一个方法,接收head节点,同时接收一个index 
	//2. index 表示是倒数第index个节点
	//3. 先把链表从头到尾遍历,得到链表的总的长度 getLength
	//4. 得到size 后,我们从链表的第一个开始遍历 (size-index)个,就可以得到
	//5. 如果找到了,则返回该节点,否则返回nulll
	public static HeroNode findLastIndexNode(HeroNode head, int index) {
		//判断如果链表为空,返回null
		if(head.next == null) {
			return null;//没有找到
		}
		//第一个遍历得到链表的长度(节点个数)
		int size = getLength(head);
		//第二次遍历  size-index 位置,就是我们倒数的第K个节点
		//先做一个index的校验
		if(index <=0 || index > size) {
			return null; 
		}
		//定义给辅助变量, for 循环定位到倒数的index
		HeroNode cur = head.next; //3 // 3 - 1 = 2
		for(int i =0; i< size - index; i++) {
			cur = cur.next;
		}
		return cur;
		
	}
	
	//方法:获取到单链表的节点的个数(如果是带头结点的链表,需求不统计头节点)
	/**
	 * 
	 * @param head 链表的头节点
	 * @return 返回的就是有效节点的个数
	 */
	public static int getLength(HeroNode head) {
		if(head.next == null) { //空链表
			return 0;
		}
		int length = 0;
		//定义一个辅助的变量, 这里我们没有统计头节点
		HeroNode cur = head.next;
		while(cur != null) {
			length++;
			cur = cur.next; //遍历
		}
		return length;
	}

}


//------------定义SingleLinkedList 管理我们的英雄
class SingleLinkedList {
	//先初始化一个头节点, 头节点不要动, 不存放具体的数据
	private HeroNode head = new HeroNode(0, "", "");
	
	
	//返回头节点
	public HeroNode getHead() {
		return head;
	}

	//添加节点到单向链表
	//思路,当不考虑编号顺序时
	//1. 找到当前链表的最后节点
	//2. 将最后这个节点的next 指向 新的节点
	public void add(HeroNode heroNode) {
		
		//因为head节点不能动,因此我们需要一个辅助遍历 temp
		HeroNode temp = head;
		//遍历链表,找到最后
		while(true) {
			//找到链表的最后
			if(temp.next == null) {//
				break;
			}
			//如果没有找到最后, 将将temp后移
			temp = temp.next;
		}
		//当退出while循环时,temp就指向了链表的最后
		//将最后这个节点的next 指向 新的节点
		temp.next = heroNode;
	}
	
	//第二种方式在添加英雄时,根据排名将英雄插入到指定位置
	//(如果有这个排名,则添加失败,并给出提示)
	public void addByOrder(HeroNode heroNode) {
		//因为头节点不能动,因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
		//因为单链表,因为我们找的temp 是位于 添加位置的前一个节点,否则插入不了
		HeroNode temp = head;
		boolean flag = false; // flag标志添加的编号是否存在,默认为false
		while(true) {
			if(temp.next == null) {//说明temp已经在链表的最后
				break; //
			} 
			if(temp.next.no > heroNode.no) { //位置找到,就在temp的后面插入
				break;
			} else if (temp.next.no == heroNode.no) {//说明希望添加的heroNode的编号已然存在
				
				flag = true; //说明编号存在
				break;
			}
			temp = temp.next; //后移,遍历当前链表
		}
		//判断flag 的值
		if(flag) { //不能添加,说明编号存在
			System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);
		} else {
			//插入到链表中, temp的后面
			heroNode.next = temp.next;
			temp.next = heroNode;
		}
	}

	//修改节点的信息, 根据no编号来修改,即no编号不能改.
	//说明
	//1. 根据 newHeroNode 的 编号 no 来修改即可
	public void update(HeroNode newHeroNode) {
		//判断是否空
		if(head.next == null) {
			System.out.println("链表为空~");
			return;
		}
		//找到需要修改的节点, 根据no编号
		//定义一个辅助变量
		HeroNode temp = head.next;
		boolean flag = false; //表示是否找到该节点
		while(true) {
			if (temp == null) {
				break; //已经遍历完链表
			}
			if(temp.no == newHeroNode.no) {
				//找到
				flag = true;
				break;
			}
			temp = temp.next;
		}
		//根据flag 判断是否找到要修改的节点
		if(flag) {
			temp.name = newHeroNode.name;
			temp.nickname = newHeroNode.nickname;
		} else { //没有找到
			System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);
		}
	}
	
	//删除节点
	//思路
	//1. head 不能动,因此我们需要一个temp辅助节点找到待删除节点的前一个节点
	//2. 说明我们在比较时,是temp.next.no 和  需要删除的节点的no比较
	public void del(int no) {
		HeroNode temp = head;
		boolean flag = false; // 标志是否找到待删除节点的
		while(true) {
			if(temp.next == null) { //已经到链表的最后
				break;
			}
			if(temp.next.no == no) {
				//找到的待删除节点的前一个节点temp
				flag = true;
				break;
			}
			temp = temp.next; //temp后移,遍历
		}
		//判断flag
		if(flag) { //找到
			//可以删除
			temp.next = temp.next.next;
		}else {
			System.out.printf("要删除的 %d 节点不存在\n", no);
		}
	}
	
	//显示链表[遍历]
	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 = temp.next;
		}
	}
}

//定义HeroNode , 每个HeroNode 对象就是一个节点
class HeroNode {
	public int no;  //编号
	public String name; //名字
	public String nickname; //昵称
	public HeroNode next; //指向下一个节点
	//构造器
	public HeroNode(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	//为了显示方法,我们重新toString
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}
	
}


-------main方法中测试------------------------------

	//进行测试
		//先创建节点
		HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
		HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
		HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
		HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");

			//创建要给链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		
		//加入,没有考虑编号。按顺序添加
		singleLinkedList.add(hero1);
		singleLinkedList.add(hero4);
		singleLinkedList.add(hero2);
		singleLinkedList.add(hero3);
----------------------------------------------

五、双向链表

package com.atguigu.linkedlist;

public class DoubleLinkedListDemo {

	public static void main(String[] args) {
		// 测试
		System.out.println("双向链表的测试");
		// 先创建节点
		HeroNode2 hero1 = new HeroNode2(1, "宋江", "及时雨");
		HeroNode2 hero2 = new HeroNode2(2, "卢俊义", "玉麒麟");
		HeroNode2 hero3 = new HeroNode2(3, "吴用", "智多星");
		HeroNode2 hero4 = new HeroNode2(4, "林冲", "豹子头");
		// 创建一个双向链表
		DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
		doubleLinkedList.add(hero1);
		doubleLinkedList.add(hero2);
		doubleLinkedList.add(hero3);
		doubleLinkedList.add(hero4);
		
		doubleLinkedList.list();
		
		// 修改
		HeroNode2 newHeroNode = new HeroNode2(4, "公孙胜", "入云龙");
		doubleLinkedList.update(newHeroNode);
		System.out.println("修改后的链表情况");
		doubleLinkedList.list();
		
		// 删除
		doubleLinkedList.del(3);
		System.out.println("删除后的链表情况~~");
		doubleLinkedList.list();
		
		
		
	}

}

// 创建一个双向链表的类
class DoubleLinkedList {

	// 先初始化一个头节点, 头节点不要动, 不存放具体的数据
	private HeroNode2 head = new HeroNode2(0, "", "");

	// 返回头节点
	public HeroNode2 getHead() {
		return head;
	}

	// 遍历双向链表的方法
	// 显示链表[遍历]
	public void list() {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空");
			return;
		}
		// 因为头节点,不能动,因此我们需要一个辅助变量来遍历
		HeroNode2 temp = head.next;
		while (true) {
			// 判断是否到链表最后
			if (temp == null) {
				break;
			}
			// 输出节点的信息
			System.out.println(temp);
			// 将temp后移, 一定小心
			temp = temp.next;
		}
	}

	// 添加一个节点到双向链表的最后.
	public void add(HeroNode2 heroNode) {

		// 因为head节点不能动,因此我们需要一个辅助遍历 temp
		HeroNode2 temp = head;
		// 遍历链表,找到最后
		while (true) {
			// 找到链表的最后
			if (temp.next == null) {//
				break;
			}
			// 如果没有找到最后, 将将temp后移
			temp = temp.next;
		}
		// 当退出while循环时,temp就指向了链表的最后
		// 形成一个双向链表
		temp.next = heroNode;
		heroNode.pre = temp;
	}

	// 修改一个节点的内容, 可以看到双向链表的节点内容修改和单向链表一样
	// 只是 节点类型改成 HeroNode2
	public void update(HeroNode2 newHeroNode) {
		// 判断是否空
		if (head.next == null) {
			System.out.println("链表为空~");
			return;
		}
		// 找到需要修改的节点, 根据no编号
		// 定义一个辅助变量
		HeroNode2 temp = head.next;
		boolean flag = false; // 表示是否找到该节点
		while (true) {
			if (temp == null) {
				break; // 已经遍历完链表
			}
			if (temp.no == newHeroNode.no) {
				// 找到
				flag = true;
				break;
			}
			temp = temp.next;
		}
		// 根据flag 判断是否找到要修改的节点
		if (flag) {
			temp.name = newHeroNode.name;
			temp.nickname = newHeroNode.nickname;
		} else { // 没有找到
			System.out.printf("没有找到 编号 %d 的节点,不能修改\n", newHeroNode.no);
		}
	}

	// 从双向链表中删除一个节点,
	// 说明
	// 1 对于双向链表,我们可以直接找到要删除的这个节点
	// 2 找到后,自我删除即可
	public void del(int no) {

		// 判断当前链表是否为空
		if (head.next == null) {// 空链表
			System.out.println("链表为空,无法删除");
			return;
		}

		HeroNode2 temp = head.next; // 辅助变量(指针)
		boolean flag = false; // 标志是否找到待删除节点的
		while (true) {
			if (temp == null) { // 已经到链表的最后
				break;
			}
			if (temp.no == no) {
				// 找到的待删除节点的前一个节点temp
				flag = true;
				break;
			}
			temp = temp.next; // temp后移,遍历
		}
		// 判断flag
		if (flag) { // 找到
			// 可以删除
			// temp.next = temp.next.next;[单向链表]
			temp.pre.next = temp.next;
			// 这里我们的代码有问题?
			// 如果是最后一个节点,就不需要执行下面这句话,否则出现空指针
			if (temp.next != null) {
				temp.next.pre = temp.pre;
			}
		} else {
			System.out.printf("要删除的 %d 节点不存在\n", no);
		}
	}

}

// 定义HeroNode2 , 每个HeroNode 对象就是一个节点
class HeroNode2 {
	public int no;
	public String name;
	public String nickname;
	public HeroNode2 next; // 指向下一个节点, 默认为null
	public HeroNode2 pre; // 指向前一个节点, 默认为null
	// 构造器

	public HeroNode2(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}

	// 为了显示方法,我们重新toString
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}

}

六、栈

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值