结构
单链表节点
//链表的节点
public class Node
{
#region 数据域
public int index;
public string str;
#endregion
#region 指针域
public Node next;//下一个节点
#endregion
//创建这个节点时,存入数据
public Node(int index,string str)
{
this.index = index;
this.str = str;
}
}
单链表对象类
public class SingleLinkList
{
public LinkNode head { get; } = new LinkNode(0, "");//头节点,这个节点没有具体数据,表示单链表的头(有些链表没有头节点)
//1.添加节点到链表末尾
//2.显示全部数据
//3.查询节点
//4.插入节点
//5.修改节点
//6.删除节点
}
1.添加节点到末尾
在SingleLinkList
类里面的方法
//添加节点到链表的末尾
public void AddLast(LinkNode node)
{
//找到当前链表的最后一个节点,将最后一个节点的next指向这个新的节点
LinkNode temp = head;//声明一个临时指针,先指向链表头
while (true)//循环遍历这个链表的节点
{
if (temp.next == null)
{
//如果当前节点的下一个节点为null,就说明当前节点就是最后一个了,因此退出循环
break;
}
//如果没有退出当前循环,就说明没有到最后一个节点,这个临时指针就指向下一个节点
temp = temp.next;
}
//退出循环就说明找到了最后一个节点,temp就是最后一个节点,连接上新的节点,添加完成
temp.next = node;
}
2.显示全部节点
在SingleLinkList
类里面的方法
就是遍历一遍链表。
//显示链表全部数据
public void Show()
{
if (head.next == null)
{
Console.WriteLine("链表为空");
return;
}
LinkNode temp = head.next;//链表不为空的话至少有一个数据
while (true)
{
Console.WriteLine(temp.index + temp.str);
if (temp.next == null)
{
break;
}
temp = temp.next;
}
}
3.查询节点
在SingleLinkList
类里面的方法
//根据str查找数据节点
public LinkNode Select(string str)
{
if (head.next == null)
{
Console.WriteLine("链表为空");
return null;
}
LinkNode temp = head.next;
bool isFind = false;//一个标记,表示有没有查询到数据
while (true)
{
if (temp.str == str)//查到了数据,退出循环,temp就是要找的节点
{
isFind = true;
break;
}
if (temp.next == null)//最后一个节点了
{
break;
}
temp = temp.next;
}
if (isFind)//找到了数据就返回temp这个数据节点
{
return temp;
}
else//没找到就返回空
{
return null;
}
}
4.插入节点
在SingleLinkList
类里面的方法
//添加的时候按顺序某个值的顺序添加,也叫插入
public void AddOrder(LinkNode node)
{
LinkNode temp = head;
bool isExist = false;//添加的节点的某个值是否 已经存在
while (true)
{
if (temp.next==null)//先判断是不是在最后,当前节点在链表最后就退出循环
{
break;
}
//当前节点的下一个节点比新节点的数据大,那么新节点插入到当前节点和下一个节点之间。(我这里是升序,降序思路反过来)
if (temp.next.index > node.index)
{
break;
}
if (temp.index == node.index)//如果发现值一样的就不能添加了,当然这个判断重复根据情况而定,有些需要有些不需要
{
isExist = true;
break;
}
temp = temp.next;
}
if (isExist)
{
Console.WriteLine("已经存在了不能添加");
return;
}
else
{
//用新节点next指向下一个节点,当前节点next指向新节点,新节点就插入到中间了,链子又连接起来了
node.next = temp.next;
temp.next = node;
}
}
5.修改节点
在SingleLinkList
类里面的方法
//通过index值修改节点数据
public void Update(LinkNode node)
{
if (head.next == null)
{
Console.WriteLine("链表为空");
return;
}
LinkNode temp = head.next;
bool isFind = false;//是否找到对应要修改的节点
while (true)
{
if (temp.index == node.index)//找到了节点
{
isFind = true;
break;
}
if (temp.next == null)//最后一个节点了
{
break;
}
temp = temp.next;
}
if (isFind)
{
//找到了就修改节点数据
temp.str = node.str;
}
else
{
Console.WriteLine("没有找到该节点");
}
}
6.删除节点
在SingleLinkList
类里面的方法
//通过index删除对应的节点
public void Delete(int index)
{
if (head.next == null)
{
Console.WriteLine("链表为空");
}
LinkNode temp = head;
bool isFind = false;//是否找到对应的节点
while (true)
{
if (temp.next == null)
{
break;
}
//temp表示要删除节点的上一个节点,如果temp直接代表这个要删除的节点,那要删除的节点的上一个和下一个节点无法连接
if (temp.next.index==index)
{
isFind = true;
break;
}
temp = temp.next;
}
if (isFind)
{
//要删除的节点是temp.next,把temp指向temp.next.next,中间temp.next没有引用就删除了
temp.next = temp.next.next;
}
else
{
Console.WriteLine("没有找到数据");
}
}
单链表题
1.得到单链表有效节点个数
就是遍历,计数
//单链表有效节点的个数,传入上方单链表的头节点,头结点不算有效节点
static int SingleLinkListCount(LinkNode head)
{
//有头节点的要去掉头节点
if (head.next == null)
{
return 0;
}
LinkNode temp = head.next;
int count = 0;
while (temp != null)
{
count++;
temp = temp.next;
}
return count;
}
2.查找单链表中倒数第k个节点
思路:
- 从链表头到尾遍历得到有效节点个数
- 得到链表的有效节点个数size后,从头开始遍历到(size-k)个就可以得到
找到返回该节点,否这返回null
/*查找单链表中倒数第k个元素*/
static LinkNode FindLast_k_Node(LinkNode head,int k)
{
if (head.next == null)//链表为空
{
return null;
}
LinkNode temp = head.next;
int size = SingleLinkListCount(head);//调用上面的方法得到链表有效数据个数
//用for限制遍历到size-k为止
for(int i = 0; i < size - k; i++)
{
//不用做什么,就迭代到下一个,最后一个就是倒数第k个元素
temp = temp.next;
}
return temp;
}
3.单链表的反转
思路:
先定义一个节点
LinkNode reverseHead = new LinkNode();
- 从头到尾遍历原来的链表,每遍历一个节点,就将其取出,并放在新的链表reverseHead的最前端
- 原来链表的
head.next=reverseHead.next
图解
static void reverseLinkList(LinkNode head)
{
//链表为空或者只有一个节点,不用反转
if (head.next == null || head.next.next == null)
{
return;
}
//定义一个辅助指针,帮助遍历原来的链表
LinkNode cur = head.next;
LinkNode next = null;//指向当前节点(cur)的下一个节点
LinkNode reverseHead = new LinkNode(0,"");//反转的开始节点
while (cur != null)
{
next = cur.next;//把当前节点的下一个节点暂时保存在next里面,因为要把reverseHead.next放在当前节点的next
cur.next = reverseHead.next;//想象cur是反转链表的第一个,就要把反转链表之后的节点都放在cur之后
reverseHead.next = cur;//cur放在reverseHead反转链表头的第一个
cur = next;//当前节点后移
}
head.next = reverseHead.next;//原链表的head指向反转链表的next
}
4.从尾到头打印单链表
思路:
方式1先反转单链表,再遍历打印。这样做会破坏原来的单链表的结构。
方式2利用栈这个数据结构,将各个节点压入栈中,利用栈的先进后出的特点,就实现了逆序打印的效果
这里使用方式2
先写一个简单的栈结构
public class SimpleStack<T>
{
T[] t = null;
int top = -1;//栈顶部默认-1,初始没有数据
public SimpleStack(int i)
{
t = new T[i];
}
//入栈
public void Push(T t)
{
if (top + 1 >= this.t.Length)
{
Console.WriteLine("栈满了");
return;
}
else
{
top++;
this.t[top] = t;
}
}
//出栈
public T Pop()
{
if (top == -1)
{
Console.WriteLine("栈没有数据");
return default(T);
}
return this.t[top--];
}
}
然后,遍历链表入栈,遍历出栈
//反转打印链表,传入第一个有效节点
static void showReverseLinkList(LinkNode node)
{
SimpleStack<LinkNode> stack = new SimpleStack<LinkNode>(10);
while (node != null)
{
stack.Push(node);
node = node.next;
}
while (true)
{
LinkNode linknode = stack.Pop();
if (linknode == null)
break;
Console.WriteLine(linknode.index+linknode.str);
}
}