今天来写一下 单链表 的总结
这次我学链表的方式是,先自己写一个C#版本的链表,来看看自己的思维是否正确,然后再看视频进行修正。从中发现了不少问题。
首先说一下链表的特点
- 动态的内存管理,初始不会固定内存,随着结点的增加不断增加
- 增加 和 删除的擅长比较方便,不需要像顺序表一样移动很多元素
- 查找的时候效率低,因为需要从结点去一个个寻找
然后说一下自己的问题
- 对循环语句不够细心,不要太马虎
- 对指针学的还不够,需要找机会重学
- 对链表结构还是需要多复习一下
- get set方法没有理解透彻
下面就先写一个C#中的结点Node类。
//我原本是直接想每个结点都 设置好前后的连接,类似双向链表
//这里写了四个构造函数,
class Node<T>//结点类 作为链表的核心元素
{
private T CurData;//存放数据
private Node<T> next;//指向下一个结点的链条
public Node(T data)
{
CurData = data;
next = null;
}
public Node(T data, Node<T> node)
{
next = node;
CurData = data;
} //第三种是只需要传递一个引用 不需要数据
public Node(Node<T> node)
{
next = node;
}
public Node()
{
CurData = default(T);
next = null;
}
//给属性提供 getset方法
public T Data
{
get
{
return CurData;
}
set
{
CurData = value;
}
}
public Node<T> Next
{
get
{
return next;
}
set
{
next = value;
}
}
}
然后就是传统C#的接口
//但是这次跟顺序表有一些不一样
在于我添加是增加了两个方法,因为链栈的特点跟顺序表不同,
他的ADD跟Insert方法是不会发生矛盾的,
所以有两种插入方式
- 一个是按照顺序加在链表的最后。
- 一个是按照index进行随意的插入。
interface LinkedList<T>
{
int GetLenth();
bool isEmty();
void Clear();
void ListInsert(T item, int index);
void ListAdd(T item);
void ListDelete(int index);
T GetEle(int index);//就是GetEle
int Locate(T value);
T this[int index] { get; }
T PreElem(int index);
T NextElem(int index);
void ListTraverse();
}
然后就是实现方法
//这次实现的关键点是
- 熟悉单链表的操作形式(找到对应的结点,进行操作)
- 增加 插入 删除 寻找 的方法跟以往的数据结构不一样
- T this[int index] {get;} 这个方法 我是第一次写好像//要记住
- 确定好这个index这里用的是 0 1 2 3 4
class MyList<T> : LinkedList<T>
{
private Node<T> head;//最初的头结点,所有方法的开始
private int ListLength;//我自己进行计数的属性
public T this[int index]
{ //第一个点 用这个方法来寻找 【特定位置】的元素
get
{ Node<T> temp = head;
for (int i = 1; i <= index; i++)
{ //假设寻找的0,开始便不成立,头结点0的数据继续
//假设寻找的1,满足条件,遍历一次,返回1的数据
//假设寻找的2,满足条件,遍历两次,不满足了。退出
temp = temp.Next;
}
return temp.Data;
}
}
public MyList()//构造函数 不需要size
{
head = null;
ListLength = 0;//置空
}
public void ListAdd(T item)
{
Node<T> newNode = new Node<T>(item);//新结点存好数据
if (head == null)
{//如果头结点 为空 //这个就是头结点
head = newNode;
ListLength++;
}
else
{//不然就把新来的结点放到链表的尾部
//要访问道链表的尾结点(利用死循环)
Node<T> temp = head;
while (true)
{
if (temp.Next != null)
{//如果 头结点的下一个 结点不为空
temp = temp.Next;
//结点内不为空 临时的变量会变成下一个
}
else
{
break;//直到某个结点后面为空 退出循环
}
}
ListLength++;
temp.Next = newNode;//把新来的结点放到尾部。
}
}
public void ListInsert(T item, int index)
{ //制作一个新的结点
//插入的时候head不能为空
Node<T> newNode = new Node<T>(item);
if (index == 0)//插入到头结点
{
newNode.Next = head;//原来的头结点还有 链表后移
head = newNode; //新的头结点
}
else
{
Node<T> temp = head;//从头开始寻找
for (int i = 1; i < index-1; i++)
{
temp = temp.Next;
}
Node<T> preNode = temp;
Node<T> currntNode = temp.Next;
preNode.Next = newNode;//正式插入的位置。
newNode.Next = currntNode;
ListLength++;
//当插入位置为1 ,不进入循环,当前结点被找到,插入
//当插入位置为2,循环一次,退出,插入
//当插入位置为3时,循环两次,退出,插入
}
}
public T PreElem(int index)
{
return this[index - 1];//方便的方法
}
public T PreElem(int index) //之前练手用的
{
if(!isEmty())//首先不能为空
{
if(index != 0)
{
Node<T> temp = head;//找头
for (int i = 1; i <= index-1 ; i++)
{
temp = temp.Next;
}
return temp.Data;
//如果为1 不循环,直接输出1的前结点head;
//如果是2 循环一次 直接输出2的前结点1;
}
else
{
return default(T);
}}
else { return default(T); }
}
public void Clear()
{
head = null;//头节点为空 所有引用消失
}
public bool isEmty()
{
return head == null;//头结点无法引用
}
public int GetLenth()
{
return ListLength;
}
public void ListDelete(int index)
{
if(index ==0)
{
head = head.Next;//头结点直接连后面的那个
ListLength--;
}
else
{
Node<T> temp = head;
for (int i = 1; i <= index-1; i++)
{
temp = temp.Next;//通过这个循环找到前结点
}
Node<T> preNode = temp;
Node<T> nextNode = temp.Next.Next;
preNode.Next = nextNode;
ListLength--;
}
}
public T GetEle(int index)
{
return this[index];
}
public int Locate(T value)
{
Node<T> temp = head;
if(temp==null)
{
return -1;
}
else
{
int index = 0;
while(true)
{
if(temp.Data.Equals(value))
{
return index;
}
else
{
if(temp.Next!=null)
{
temp = temp.Next;
}
else
{ break; }//没有满足情况
}
}
return -1;
}
}
}
就这样,这样的一个链表就完成了,我最大的问题还是不够熟练,还是需要反复多看一次这些代码。(尤其了循环语句都弄错几次)
本来想一次性把C++的链表也po出来,但是感觉自己还是没有掌握的很好,就放弃了,继续加油。