代码依旧用c#的写的增加了修改删除合并的方法,我会坚持写下去,如有不对 之处希望大家斧正,注释写的比较详细。有什么问题欢迎留言。
链表节点类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 线性表ccc
{
public class MyLinkListNode<T>
{
public MyLinkListNode()
{
}
public T data;
public MyLinkListNode(T data)
{
this.data = data;
}
//下一个节点
public MyLinkListNode<T> next;
}
}
链表类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 线性表ccc
{
public class MyLinkList<T>
{
//链表长度
private int count;
public int Count
{
get { return count; }
}
//链表头
MyLinkListNode<T> head;
public MyLinkList()
{
head = new MyLinkListNode<T>();
head.next = null;
}
public MyLinkList(T[] nums):this()
{
AddItem(nums);
}
/// <summary>
/// 增加一组数组到链表里
/// </summary>
/// <param name="nums"></param>
private void AddItem(T[] nums)
{
foreach (T item in nums)
{
AddObject(item);
}
}
/// <summary>
/// 把一个节点加到头节点后面
/// </summary>
/// <param name="item"></param>
private void AddObject(T item)
{
//这里给单链表开辟了表长的空间
MyLinkListNode<T> p = new MyLinkListNode<T>();
p.data = item;
//设置原来的父节点的子节点为 现子节点的父节点
p.next = head.next;
//建立头节点与子节点的关系
head.next = p;
count++;
}
/// <summary>
/// 获取链表某个位置的元素
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public T GetElem(int index)
{
MyLinkListNode<T> p = head.next;
int j = 0;
while(p!=null&&index>j)
{
p = p.next;
j++;
}
if (p==null||j>index)
{
throw new Exception("超出界限");
}
return p.data;
}
/// <summary>
/// 向链表插入一个元素
/// </summary>
/// <param name="index"></param>
/// <param name="elem"></param>
/// <returns></returns>
public void InsertElem(int index,T elem)
{
MyLinkListNode<T> p = head;
int j = 0;
if (index>=count)
{
throw new Exception("插入的索引超界");
}
while (p != null&&index>j)
{
p = p.next;
j++;
}
MyLinkListNode<T> newnode = new MyLinkListNode<T>(elem);
//让它指向原来上一个节点指向的元素
newnode.next = p.next;
//让老节点指向插入的新节点
p.next = newnode;
count++;
}
/// <summary>
/// 删除一个元素
/// </summary>
public void DeleteElem(int index)
{
//把头节点赋值给一个临时节点
MyLinkListNode<T> p = head;
int j = 0;
// =的情况也不行因为链表最多取到count - 1
if (index > count)
{
throw new Exception("删除的索引超界");
}
//取到删除节点的上一个节点
while (p != null&&index > j)
{
p = p.next;
j++;
}
//删除P.next让p.next指向p.next的next; 此时原来的p.next没有引用会被GC自动销毁
p.next = p.next.next;
//删除之后count要-1
count--;
//GC.Collect();
}
/// <summary>
/// 修改链表index位置的值
/// </summary>
/// <param name="index"></param>
/// <param name="elem"></param>
public void UpDateElem(int index,T elem)
{
MyLinkListNode<T> p = head;
// =的情况也不行因为链表最多取到count - 1
if (index >= count)
{
throw new Exception("删除的索引超界");
}
int j = 0;
//定位要要修改的位置
while (index >= j)
{
p = p.next;
j++;
}
p.data = elem;
}
/// <summary>
/// 把La和Lb归并成一个单链表,由于不知道类型传一个回调函数进来
/// </summary>T
/// <param name="ListA"></param>
/// <param name="ListB"></param>
/// <returns></returns>
public MyLinkList<T> MergeList(MyLinkList<T> La,Func<T,T,bool> func)
{
MyLinkList<T> Lc = new MyLinkList<T>();
Lc.count = La.count + count;
MyLinkListNode<T> pa, pb, pc;
pb = La.head.next;
pa = this.head.next;
//Lc.head和pc指向同一片空间
pc = Lc.head;
while (pa != null && pb!=null)
{
//如果pa<=pb
if (func(pa.data,pb.data))
{
pc.next = pa;
//让pc指针前移
pc = pa;
//pa的指针前移
pa = pa.next;
}
else
{
pc.next = pb;
pc = pb;
pb = pb.next;
}
}
if (pb != null)
{
//1次就Pb后面链着的都归了pc
pc.next = pb;
//这时候pc的指针也得前移
pc = pc.next;
}
else
{
pc.next = pa;
pc = pc.next;
}
return Lc;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
MyLinkListNode<T> p = head.next;
while (p != null)
{
sb.Append(p.data + " ");
p = p.next;
}
return sb.ToString();
}
}
}
实际上操作 都是引用的各种变换 。
测试代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 线性表ccc
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("请输入测试数组类似5 4 3");
string[] s = Console.ReadLine().Split(' ');
int[] nums = new int[s.Length];
for (int i = 0; i < s.Length; i++)
{
nums[i] = Convert.ToInt32(s[i]);
}
//初始化的时候存的类似于 3=>4=>5
MyLinkList<int> ml = new MyLinkList<int>(nums);
Console.WriteLine("链表输出的结果是");
Console.WriteLine(ml.ToString());
while (true)
{
Console.WriteLine("请输入插入的位置");
int indexInsert = int.Parse(Console.ReadLine());
Console.WriteLine("请输入插入的值");
int value = int.Parse(Console.ReadLine());
ml.InsertElem(indexInsert, value);
Console.WriteLine("打印链表结果");
Console.WriteLine(ml.ToString());
Console.WriteLine("请输入要删除的索引");
int indexDel = int.Parse(Console.ReadLine());
ml.DeleteElem(indexDel);
Console.WriteLine(ml.ToString());
Console.WriteLine("请输入要修改的索引");
int indexUpdate = int.Parse(Console.ReadLine());
Console.WriteLine("请输入要修改的值");
int valueUpdate = int.Parse(Console.ReadLine());
ml.UpDateElem(indexUpdate, valueUpdate);
Console.WriteLine("打印链表结果");
Console.WriteLine(ml.ToString());
Console.WriteLine("请输入链表B类似5 4 3");
string[] sB = Console.ReadLine().Split(' ');
int[] numsB = new int[sB.Length];
for (int i = 0; i < s.Length; i++)
{
numsB[i] = Convert.ToInt32(sB[i]);
}
MyLinkList<int> mlB = new MyLinkList<int>(numsB);
MyLinkList<int> mlC = ml.MergeList(mlB, (x,y)=>x<=y);
Console.WriteLine("合并两个链表的结果是");
Console.WriteLine(mlC.ToString());
Console.WriteLine();
}
}
}
}
结果如图:
算法分析:
删除要找到 删除节点的前一个节点 故一次循环时间复杂度是O(n)
修改也要找到删除节点 时间复杂度也是O(n)
合并操作一共循环m+n次 时间复杂度是O(m+n) 即O(n)
最后更正一下上一篇的一个错误 遍历的时间复杂度是O(n) 不需要循环GetElem详细代码 请参考 这篇里MyLinkList 重载的ToString()方法