本文是学习尚硅谷韩顺平老师的数据结构与算法后,自己做的笔记,代码都是照着视频敲得,不知道会不会有转载的嫌疑,若有,麻烦请提醒本人,谢谢!
欢迎留言讨论!
数据结构
概述:
数据结构是一种研究组织数据方式的学科,学好数据结构可以编写出更漂亮、有效率的代码。
1、什么是数据结构?
数据结构是指由相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。
2、数据的储存结构
是指由相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。
链式存储:链式存储结构:是把数据元素存放在内存中的任意存储单元里,也就是可以把数据存放在内存的各个位置。这些数据在内存中的地址可以是连续的,也可以是不连续的。
二者之间储存地址的连续性不同,在进行操作时的特点不同。
3、数据的逻辑结构
集合结构:集合结构中的数据元素同属于一个集合,他们之间是并列的关系,除此之外没有其他关系。
线性结构:线性结构中的元素存在一对一的相互关系。数据和数据之间是有关系的。
(非线性结构)
树形结构:树形结构中的元素存在一对多的相互关系。
图形结构:图形结构中的元素存在多对多的相互关系。
链表:
概述:
链表(Linked list)由一些节点组成,物理存储非连续的线性表。其中每个节点都会存储下个节点的指针,由于实际存储空间不连续,对链表插入节点,删除节点可以达到O(1)的复杂度,但是对一个节点的访问需要O(n)的时间。
链表有单向链表,双向链表。
单向链表:
单向链表的每个节点有数据项和指针(指向下个节点地址数据)组成,表头没有数据项,只有指向下一个节点的指针。表尾节点指向下一个节点pNext指针为NULL(空)。
代码演示:
package linkedlist;
import javax.sound.sampled.ReverbType;
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, "林冲", "豹子头");
HeroNode hero5 = new HeroNode(4, "林冲", "豹子头头");
SingleLinkedList singleLinkedList = new SingleLinkedList();
singleLinkedList.add(hero1);
singleLinkedList.add(hero2);
singleLinkedList.add(hero3);
singleLinkedList.add(hero4);
singleLinkedList.list();
singleLinkedList.del(2);
singleLinkedList.list();
reverseList(singleLinkedList.getHead());
singleLinkedList.list();
}
public static void reverseList(HeroNode head) {
if(head.next == null&&head.next.next == null) {
return ;
}
HeroNode reverseListhead = new HeroNode(0,"","");
HeroNode cur = head.next;
HeroNode next = null;
while(cur!=null) {
//采用前置法
if(cur.next==null) {
cur.next = reverseListhead.next;
reverseListhead.next = cur;
break;
}
next = cur.next;
cur.next = reverseListhead.next;
reverseListhead.next = cur;
cur = next;
}
head.next = reverseListhead.next;
}
}
//定义SingleLinkedList管理我们的英雄
class SingleLinkedList{
//定义链表头节点
HeroNode headnode = new HeroNode(0,"","");
//返回头节点
public HeroNode getHead() {
return headnode;
}
//添加节点到单向链表
//思路,当不考虑编号顺序时
//1. 找到当前链表的最后节点
//2. 将最后这个节点的next 指向 新的节点
public void add(HeroNode heroNode) {
if(headnode.next == null) {
headnode.next = heroNode;
return;
}
HeroNode temp = headnode.next;
while (true) {
if(temp.next == null) {
break;
}else {
temp = temp.next;
}
//找到最后节点后把目标节点放到最后
}
temp.next = heroNode;
}
public void update(HeroNode newHeroNode) {
//判断是否为空
if(headnode.next == null) {
System.out.println("链表为空!!");
return;
}
//找到需要修改的节点,并且用一个辅助节点记录
HeroNode temp = headnode.next;
boolean flag = false;
while(true) {
if(temp == null) {
break ;
}
if(temp.no == newHeroNode.no){
flag = true;
break;
}
temp = temp.next;
}
if(flag) {
temp.nickname = newHeroNode.nickname;
temp.name = newHeroNode.name;
}else {
System.out.println("找不到目标节点,更新失败!");
}
}
//删除节点
public void del(int no ) {
if(headnode.next == null) {
return ;
}
HeroNode temp = headnode.next;
boolean flag = false;
while(true) {
if(temp == null) {
break;
}else if(temp.next.no == no) {
flag = true;
break;
}else {
temp = temp.next;
}
}
if(flag) {
temp.next = temp.next.next;
}else {
System.out.printf("查找的%d节点不存在!",no);
}
}
//显示链表
public void list() {
if(headnode.next==null) {
System.out.println("链表为空!");
return ;
}
HeroNode temp = headnode.next;
while(true) {
if(temp == null) {
break;
}else {
System.out.println(temp);
temp = temp.next;
}
}
}
//返回链表长度
public int getLength() {
if(headnode.next==null) {
System.out.println("链表为空!");
return 0;
}
HeroNode temp = headnode.next;
int count = 0;
while(true) {
if(temp==null) {
break;
}else {
count++;
temp = temp.next;
}
}
return count;
}
}
class HeroNode{
public int no;
public String name;
public String nickname;
public HeroNode next; //指向下一个节点
public HeroNode(int no, String name, String nickname) {
super();
this.no = no;
this.name = name;
this.nickname = nickname;
}
//重写tostring
@Override
public String toString () {
return "HeroNode[no = "+no + ",name" + name + ",nickname" + nickname+"]";
}
}
双向链表
双向链表有别于单向的,每个节点除了数据项外有两个指针分别指向前一个节点和后一个节点,占用空间会大一些,可以实现从头到尾的遍历,又可以从尾到头遍历。
环形链表
环形链表是单链表的一种特殊形式,在表尾的下一个指针指向头指针。形成环状结构。
用单链表实现约瑟夫问题
代码实现:
package linkedlist;
public class Josephu {
public static void main(String[] args) {
CircleSingleLinkList circleSingleLinkedList = new CircleSingleLinkList();
circleSingleLinkedList.add(5);
circleSingleLinkedList.shouBoy();
circleSingleLinkedList.countBoy(1, 2, 5);
}
}
class CircleSingleLinkList{
//创建一直当前头节点
private Boy first= new Boy(-1);
//添加小孩节点,构建成一个环形链表
public void add(int nums){
//对数字进行校验
if(nums<1) {
System.out.println("数字的值不正确!");
return;
}
Boy curBoy = null; //辅助变量帮助记录
for(int i = 0;i<nums;i++) {
//根据标号创建小孩节点
Boy boy = new Boy(i+1);
//如果是第一个小孩
if(i==0) {
first = boy;
boy.setBoy(first);
curBoy = first;
}else {
curBoy.setBoy(boy);
boy.setBoy(first);
curBoy = boy;
}
}
}
//遍历环形链表
public void shouBoy() {
if(first==null) {
System.out.println("没有任何小孩!");
}
Boy curBoy = first;
while(true) {
System.out.printf("小孩的编号%d,\n",curBoy.getNo());
if(curBoy.getBoy()==first ) {
break;
}
curBoy = curBoy.getBoy();
}
}
//根据用户输入计算出小孩出圈的顺序
public void countBoy(int startNo,int countNum,int nums) {
//先对数据进行校验
if(first == null||startNo < 1||startNo>nums) {
System.out.println("参数输入有误,请重新输入!");
return ;
}
//创建辅助指针,帮助小孩出圈
Boy helper =first;
while(true) {
if(helper.getBoy() == first) {
break;
}
helper = helper.getBoy();
}
for(int i =0;i<startNo - 1;i++) {
first = first.getBoy();
helper = helper.getBoy();
}
while(true) {
if(helper == first ) {
break;
}
for(int i =0;i<countNum - 1;i++) {
first = first.getBoy();
helper = helper.getBoy();
}
System.out.printf("小孩%d出圈\n",first.getNo());
first = first.getBoy();
helper.setBoy(first);
}
System.out.printf("最后留在全圈中的小孩编号是%d\n",first.getNo());
}
}
class Boy{
private int no;
private Boy boy;
public Boy(int no) {
super();
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Boy getBoy() {
return boy;
}
public void setBoy(Boy boy) {
this.boy = boy;
}
}