数据结构——简单概述与链表知识总结

本文是学习尚硅谷韩顺平老师的数据结构与算法后,自己做的笔记,代码都是照着视频敲得,不知道会不会有转载的嫌疑,若有,麻烦请提醒本人,谢谢!

欢迎留言讨论!


数据结构

概述:

数据结构是一种研究组织数据方式的学科,学好数据结构可以编写出更漂亮、有效率的代码。

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;
	}
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链表(Linked List)是一种常见的数据结构,它是由一系列节点组成的,每个节点包含一个数据元素和一个指向下一个节点的指针。链表中的节点可以在运行时动态添加或删除,这使得链表在某些场景下比数组更加适用。 在 Python 中,链表可以使用类来实现。下面是一个简单链表实现: ```python class Node: def __init__(self, data): self.data = data self.next = None class LinkedList: def __init__(self): self.head = None def add_node(self, data): new_node = Node(data) if self.head is None: self.head = new_node else: current = self.head while current.next is not None: current = current.next current.next = new_node def remove_node(self, data): if self.head is None: return if self.head.data == data: self.head = self.head.next else: current = self.head while current.next is not None: if current.next.data == data: current.next = current.next.next break current = current.next def print_list(self): current = self.head while current is not None: print(current.data, end=' ') current = current.next print() ``` 这个链表实现包含两个类:Node 和 LinkedList。Node 表示链表中的节点,LinkedList 则是整个链表。Node 类中包含了数据元素和指向下一个节点的指针,LinkedList 类中包含了链表的头节点。add_node 方法用于向链表中添加节点,remove_node 方法用于从链表中删除节点,print_list 方法用于打印整个链表链表的常见操作包括遍历、插入、删除等。下面是一些链表的常见操作: 1. 遍历链表 遍历链表可以通过一个 while 循环实现,从头节点开始遍历,直到遇到 None 为止。 ```python def print_list(self): current = self.head while current is not None: print(current.data, end=' ') current = current.next print() ``` 2. 插入节点 在链表中插入节点需要注意节点的顺序。可以先找到要插入的位置,然后将新节点的指针指向下一个节点,再将前一个节点的指针指向新节点。 ```python def insert_node(self, data, position): new_node = Node(data) if position == 0: new_node.next = self.head self.head = new_node else: current = self.head for i in range(position - 1): current = current.next if current is None: return new_node.next = current.next current.next = new_node ``` 3. 删除节点 在链表中删除节点需要先找到要删除的位置,然后将前一个节点的指针指向下一个节点。需要注意删除头节点和删除中间节点的情况。 ```python def remove_node(self, data): if self.head is None: return if self.head.data == data: self.head = self.head.next else: current = self.head while current.next is not None: if current.next.data == data: current.next = current.next.next break current = current.next ``` 链表的时间复杂度为 O(n),其中 n 是链表的长度。链表的优点是可以在运行时动态添加或删除节点,并且可以节省内存空间。缺点是不能像数组那样随机访问元素,需要从头节点遍历整个链表才能访问到某个元素。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值