一、定义相关
1、线性表:由n个相同的类型的数据元素组成的有限的序列。
特点:(1)有且仅有一个开始结点,没有直接前趋,仅有一个后继结点。
(2)有且仅有一个终端结点,没有直接后继,仅有一个直接前驱。
分类:顺序表、单链表、双链表、循环链表
操作:
interface IlinarList<T> { void InsertNode(T a,int i);//插入操作 void DeleteNode(int i);//删除操作 T SearchNode(int i);//查找表元素 T SearchNode(T value);//定位表元素 int GetLength();//求取表长度 void Clear();//清空操作 bool IsEmpty();//判断线性表是否为空 }
二、代码分析
1、顺序表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
//用顺序链表解决 public class SeqList<T>:IlinarList<T> { private int maxsize;//顺序表的最大容量 private T[] data;//定义一个用于存储数据元素的数组 private int length;//顺序表的实际长度 public int Maxsize{ get { return maxsize; } set { maxsize = value; } } public int Length { get { return length; } set { length = value; } } //初始化线性表 public SeqList(int size) { maxsize = size; data=new T[maxsize]; length = 0; } //判断顺序表是否为满 public bool IsFull() { if (length==maxsize) { return true; } else { return false; } } //判断顺序表是否为空 public bool IsEmpty() { if (length==0) { return true; } else { return false; } } //清空操作 public void Clear() { length = 0; } //求取顺序表的长度 public int GetLength() { return length; } //在顺序表的末尾添加元素 public void InsertNode(T a) { if (IsFull()==true) { Console.WriteLine("List is full"); return; } data[length] = a; length = length + 1; } //在顺序表的第i个位置插入一个数据元素 public void InsertNode(T a, int i) { if (IsFull() == true) { Console.WriteLine("List is full"); return; } if (i < 1 || i > length+1) { Console.WriteLine("Position is error"); return; } else { data[i - 1] = a; for (int j = i; j < length;j++ ) { data[j+1] = data[j ]; } } length++; } //删除顺序表中的第i个元素 public void DeleteNode(int i) { if (IsEmpty() == true) { Console.WriteLine("List is empty ."); return; } if (i < 1 || i > length) { Console.WriteLine("Position is error"); return; } for (int j = i ; j < length; j++) { data[j-1] = data[j]; } length--; } //获得顺序表中的第i个元素 public T SearchNode(int i) { if (IsEmpty() == true || i < 1 || i > length) { Console.WriteLine("List is empty or position is error !"); return default(T); } return data[i-1]; } //在顺序表中查找值为value的数据元素 public T SearchNode(T a) { if (IsEmpty() == true) { Console.WriteLine("List is empty !"); return default(T); } int i = 0; for ( i = 0; i < length; i++) { if (data[i].ToString().Equals(a.ToString())) { break; } } if(i>length) { return default(T); } return data[i]; } }
2、单链表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class SLinkList<T>:IlinarList<T> { private SNode<T> start; int length; public SLinkList() { start = null; } public bool IsEmpty() { if (start == null) { return true; } else { return false; } } public int GetLength() { return length; } public void Clear() { start = null; } public void InsertNode(T a) { if (start == null) { start=new SNode<T>(a); length++; return; } SNode<T> current = start; while (current.Next != null) { current = current.Next; } current.Next = new SNode<T>(a); length++; } //在单链表的第i个位置前插入一个数据元素 public void InsertNode(T a, int i) { SNode<T> current; SNode<T> previous; if (i < 1 || i > length + 1) { Console.WriteLine("Position is error !"); return; } SNode<T>newNodee=new SNode<T>(a); //在空链表或者链表的第一个位置插入第一个元素 if (i == 1) { newNodee.Next = start; start = newNodee; length++; return; } //在单链表的两个元素之间插入一个元素 current = start; previous = null; int j = 1; while (current != null && j < i) { previous = current; current = current.Next; j++; } if (j == i) { previous.Next = newNodee; newNodee.Next = current; length++; } } //删除单链表的第i个元素 public void DeleteNode(int i) { if (IsEmpty() || i < 1||i>length+1) { Console.WriteLine("SLinkList is empty or position is error !"); } SNode<T> current = start; if (i == 1) { start = current.Next; length--; return; } SNode<T> previous = null; int j = 1; while (current.Next != null && j < i) { previous = current; current = current.Next; j++; } if (i == j) { previous.Next = current.Next; current = null; length--; } else { Console.WriteLine("the ith node is not exist !"); } } public T SearchNode(int i) { if (IsEmpty()) { Console.WriteLine("List is empty !"); return default(T); } SNode<T> current = start; int j = 1; while (current.Next != null && j < i) { current = current.Next; j++; } if (j == i) { return current.Data; } else { Console.WriteLine("This ith node is not exit !"); return default(T); } } public T SearchNode(T value) { if (IsEmpty()) { Console.WriteLine("List is empty !"); return default(T); } SNode<T> current = start; int i = 1; while (!current.Data.ToString().Contains((value.ToString())) && current != null) { current = current.Next; i++; } if (current != null) { return current.Data; } else { return default(T); } } }
3、双链表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class DLinkList<T>:IlinarList<T> { private DbNode<T> start; private int length; public DLinkList() { start = null; } public bool IsEmpty() { if (start == null) { return true; } else { return false; } } public void Clear() { start = null; } public int GetLength() { return length; } //在双向链表的末尾追加数据元素 public void InsertNode(T a) { DbNode<T>newnode=new DbNode<T>(a); if (IsEmpty()) { start = newnode; length++; return; } DbNode<T> current = start; while (current.Next != null) { current = current.Next; } current.Next = newnode; newnode.Prev = current; newnode.Next = null; length++; } //在双向链表的第i个数据元素的位置前插入一个数据元素 public void InsertNode(T a, int i) { DbNode<T> current; DbNode<T> previous; if (i < 1) { Console.WriteLine("Position is erroe !"); return; } DbNode<T> newNode=new DbNode<T>(a); //如果这个位置是第一个位置 if (i == 1) { newNode.Next = start; start = newNode; length++; return; } //在双向链表的两个元素间插入一个元素 current = start; previous = null; int j = 1; while (current != null && j < i) { previous = current; current = current.Next; j++; } if (j == i) { newNode.Next = current; newNode.Prev = previous; if(current!=null) current.Prev = newNode; previous.Next = newNode; length++; } } //删除双向链表的第i个数据元素 public void DeleteNode(int i) { if (IsEmpty() || i < 1) { Console.WriteLine("Link is empty or position is error !"); } DbNode<T> current = start; if (i == 1) { start = current.Next; length--; return; } DbNode<T> previous = null; int j = 1; while (current.Next != null && j < i) { previous = current; current = current.Next; j++; } if (j == i) { previous.Next = current.Next; if (current.Next != null) { current.Next.Prev = previous; previous = null; current = null; length--; } } else { Console.WriteLine("The ith node is not exist !"); } } //获取双向链表中查找第i个数据元素 public T SearchNode(int i) { if (IsEmpty()) { Console.WriteLine("List is empty !"); return default(T); } DbNode<T> current = start; int j = 1; while (current.Next != null && j < i) { current = current.Next; j++; } if (j == i) { return current.Data; } else { Console.WriteLine("The ith node is not exist !"); return default(T); } } //在双向链表中查找值为value的数据元素 public T SearchNode(T value) { if (IsEmpty()) { Console.WriteLine("List is empty !"); return default(T); } DbNode<T> current = start; int i = 1; while (!current.Data.ToString().Contains(value.ToString()) && current != null) { current = current.Next; i++; } if (current != null) { return current.Data; } else { return default(T); } } }
4、循环链表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class ClinkList<T>:IlinarList<T> { private ClinkNode<T> start; int length; public ClinkList() { start = null; } public bool IsEmpty() { if (start == null) { return true; } else { return false; } } public int GetLength() { return length; } public void Clear() { start = null; } //在循环链表的末尾追加数据元素 public void InsertNode(T a) { if (start == null) { start=new ClinkNode<T>(a); length++; return; } ClinkNode<T> current = start; while (current.Next != null) { current = current.Next; } ClinkNode<T> temp=new ClinkNode<T>(a); current.Next = temp; temp.Next = start; length++; } //在单链表的第i个位置前插入一个数据元素 public void InsertNode(T a, int i) { ClinkNode<T> current; ClinkNode<T> previous; if (i < 1 || i > length + 1) { Console.WriteLine("Position is error !"); return; } ClinkNode<T> newNodee = new ClinkNode<T>(a); //在空链表或者链表的第一个位置插入第一个元素 if (i == 1) { newNodee.Next = start; start = newNodee; length++; return; } //在单链表的两个元素之间插入一个元素 current = start; previous = null; int j = 1; while (current != null && j < i) { previous = current; current = current.Next; j++; } if (j == i) { previous.Next = newNodee; newNodee.Next = current; length++; } } //删除单链表的第i个元素 public void DeleteNode(int i) { if (IsEmpty() || i < 1||i>length+1) { Console.WriteLine("SLinkList is empty or position is error !"); } ClinkNode<T> current = start; if (i == 1) { start = current.Next; length--; return; } ClinkNode<T> previous = null; int j = 1; while (current.Next != null && j < i) { previous = current; current = current.Next; j++; } if (i == j) { previous.Next = current.Next; current = null; length--; } else { Console.WriteLine("the ith node is not exist !"); } } public T SearchNode(int i) { if (IsEmpty()) { Console.WriteLine("List is empty !"); return default(T); } ClinkNode<T> current = start; int j = 1; while (current.Next != null && j < i) { current = current.Next; j++; } if (j == i) { return current.Data; } else { Console.WriteLine("This ith node is not exit !"); return default(T); } } public T SearchNode(T value) { if (IsEmpty()) { Console.WriteLine("List is empty !"); return default(T); } ClinkNode<T> current = start; int i = 1; while (!current.Data.ToString().Contains((value.ToString())) && current != null) { current = current.Next; i++; } if (current != null) { return current.Data; } else { return default(T); } } }
三、应用:在学生成绩表中的应用
1、顺序表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class SNode<T> { private T data;//数据域 private SNode<T> next;//引用域 public SNode(T value, SNode<T> p) { data = value; next = p; } public SNode(SNode<T> p) { next = p; } public SNode(T value) { data = value; } public T Data { get { return data; } set { data = value; } } public SNode<T> Next { get { return next; } set { next = value; } } }
2、单链表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class ClinkNode<T> { private T data;//数据域 private ClinkNode<T> next;//引用域 public ClinkNode(T value, ClinkNode<T> p) { data = value; next = p; } public ClinkNode(ClinkNode<T> p) { next = p; } public ClinkNode(T value) { data = value; } public T Data { get { return data; } set { data = value; } } public ClinkNode<T> Next { get { return next; } set { next = value; } } }
3、双链表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class DbNode<T> { private T data;//数据域 private DbNode<T> prev;//前驱引用域 private DbNode<T> next;//后驱引用域 //构造器 public DbNode(T val, DbNode<T> p) { data = val; next = p; } public DbNode(DbNode<T> p) { next = p; } public DbNode(T val) { data = val; next = null; } public DbNode() { data = default(T); next = null; } public T Data { get { return data; } set { data = value; } } public DbNode<T> Prev { get { return prev; } set { prev = value; } } public DbNode<T> Next { get { return next; } set { next = value; } } }
4、循环链表
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class ClinkNode<T> { private T data;//数据域 private ClinkNode<T> next;//引用域 public ClinkNode(T value, ClinkNode<T> p) { data = value; next = p; } public ClinkNode(ClinkNode<T> p) { next = p; } public ClinkNode(T value) { data = value; } public T Data { get { return data; } set { data = value; } } public ClinkNode<T> Next { get { return next; } set { next = value; } } }
5、学生成绩表类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class StuNode { private string _stu_no; private string _stu_name; private int _stu_score; public string Stu_no { get { return _stu_no; } set { _stu_no = value; } } public string Stu_name { get { return _stu_name; } set { _stu_name = value; } } public int Stu_score { get { return _stu_score; } set { _stu_score = value; } } public StuNode(string stuNo, string stuName, int stuScore) { this._stu_no = stuNo; this._stu_name = stuName; this._stu_score = stuScore; } public override string ToString() { return _stu_no + _stu_name; } }
应用:
private static void Main(string[] args) { IlinarList<StuNode> stuList = null; //SeqList<StuNode> stuList = null; #region 选择存储结构类型 Console.WriteLine("请选择存储结构的类型:1、顺序表,2、单链表,3、双链表,4、循环链表"); char selectFlag = Convert.ToChar(Console.ReadLine()); switch (selectFlag) { case '1': Console.WriteLine("请输入学生的个数"); int maxsize = Convert.ToInt32(Console.ReadLine()); stuList = new SeqList<StuNode>(maxsize); break; case '2': stuList=new SLinkList<StuNode>(); break; case '3': stuList=new DLinkList<StuNode>(); break; case '4': stuList=new ClinkList<StuNode>(); break; } #endregion while (true) { Console.WriteLine("请输入操作选项:"); Console.WriteLine("1、添加学生成绩"); Console.WriteLine("2、删除学生成绩"); Console.WriteLine("3、按姓名查询学生成绩"); Console.WriteLine("4、按学号查询学生成绩"); Console.WriteLine("5、查看学生全部信息"); Console.WriteLine("6、退出"); selectFlag = Convert.ToChar(Console.ReadLine()); switch (selectFlag) { #region 添加学生成绩 case '1': { char falg; do { string stuNo; string stuName; int stuScore; Console.WriteLine("请输入学号"); stuNo = Console.ReadLine(); Console.WriteLine("请输入姓名"); stuName = Console.ReadLine(); Console.WriteLine("请输入成绩"); stuScore = Convert.ToInt32(Console.ReadLine()); StuNode newStuNode = new StuNode(stuNo, stuName, stuScore); //添加到首部 if (stuList.GetLength() == 0) { stuList.InsertNode(newStuNode,1); } //添加到尾部 else if (newStuNode.Stu_score > stuList.SearchNode(stuList.GetLength()).Stu_score) { stuList.InsertNode(newStuNode, stuList.GetLength() + 1); } else { for (int i = 1; i <= stuList.GetLength(); i++) { if (newStuNode.Stu_score <= (stuList.SearchNode(i).Stu_score)) { stuList.InsertNode(newStuNode, i); break; } } } Console.WriteLine("还有学生成绩输入吗?(Y/N)"); falg = Convert.ToChar(Console.ReadLine()); } while (falg == 'Y'); break; } #endregion #region 删除学生成绩 case '2': { StuNode temp; Console.WriteLine("请输入要删除的学生的学号:"); string stuNo = Console.ReadLine(); for (int i = 1; i <= stuList.GetLength(); i++) { temp = stuList.SearchNode(i); if (temp.Stu_no == stuNo) { stuList.DeleteNode(i); break; } } break; } #endregion #region 按姓名查询成绩 case '3': { StuNode temp; Console.WriteLine("请输入你要查询学生的姓名"); string stuName = Console.ReadLine(); for (int i = 1; i <= stuList.GetLength(); i++) { temp = stuList.SearchNode(i); if (temp.Stu_name == stuName) { Console.WriteLine("姓名为{0}的成绩是{1}",stuName,temp.Stu_score); break; } } break; } #endregion #region 按学号查询成绩 case '4': { StuNode temp; Console.WriteLine("请输入要查找的学生的学号"); string stuNo = Console.ReadLine(); for (int i = 1; i < stuList.GetLength(); i++) { temp = stuList.SearchNode(i); if (temp.Stu_no == stuNo) { Console.WriteLine("学号为{0}的成绩是{1}",stuNo,temp.Stu_score); break; } } break; } #endregion #region 查看全部学生信息 case '5': { StuNode temp; for (int i = 1; i <= stuList.GetLength(); i++) { temp = stuList.SearchNode(i); Console.WriteLine("\t{0}\t{1}\t{2}",temp.Stu_no,temp.Stu_name,temp.Stu_score); } break; } #endregion #region 退出 case '6': { return; } #endregion } Console.WriteLine("按任意键退出......"); Console.ReadKey(); } }
}
四、实际应用
问题描述:
约瑟夫问题的一种描述是:编号为1、2....n的n个人按顺时针方向围座一圈,每人拿一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向从1开始顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他的顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列。设计一个程序求出出列顺序。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace 循环链表实现约瑟夫环问题 { internal class Program { public static int NodeLength = 1; //记录循环链表的长度,同时也是链表节点的序号 public static int markNum = 0; //链表节点的序号 private static void Main(string[] args) { Console.WriteLine("请输入节点的值(以-1作为输入的结束):"); int ConsoleRead = Convert.ToInt32(Console.ReadLine()); //接受用户输入的数据,作为第一个节点 Node CircleNode = new Node(ConsoleRead, NodeLength); //构造一个新节点 CircleNode.Next = CircleNode; //将第一个节点的尾部指针指向该节点自身 Node cursor = CircleNode; //设置一个指针 Console.WriteLine("请输入节点的值(以-1作为输入的结束):"); int input = Convert.ToInt32(Console.ReadLine()); while (input != -1) //以-1作为输入的终结 { NodeLength++; //每增加一个新节点,链表长度加1 Node nd = new Node(input, NodeLength); nd.Next = cursor.Next; //将新节点加在链表指针的后面 cursor.Next = nd; //插入新的节点,形成循环链表 cursor = cursor.Next; //将指针后移动一位 Console.WriteLine("请输入节点的值(以-1作为输入的结束):"); input = Convert.ToInt32(Console.ReadLine()); } //调用函数处理节点的删除 DeleteElem(2, NodeLength, CircleNode); Console.ReadKey(); } //处理节点的删除的函数 public static void DeleteElem(int num, int Length, Node nd) { #region int DelData = 0; //删除的节点的数据域的值 if (Length == 0) //链表的长度为0说明节点已经删完,返回 { return; } int position = num%Length; //要删除的节点的位置 if (Length == 1) //删除最后一个节点 { DelData = nd.data; //删除节点的值 Console.WriteLine("删除的节点的序号:{0}; 删除的节点的数据域的值:{1}", nd.mark, DelData.ToString()); return; } Node q = nd; Node p = q; //设置两个指针节点 //寻找要删除的节点 int i = 1; while (q.Next != q && i < position && q != null) { p = q; q = q.Next; i++; } #endregion #region if (q.Next != q && q.Next != null) { if (Length <= 2 && position == 1) //剩下两个元素 { DelData = p.data; markNum = p.mark; q = q.Next; q.Next = p.Next; } else if (Length <= 2 && position == 0) { q = q.Next; DelData = q.data; markNum = q.mark; p.Next = q.Next; } else if (p == q && Length > 2) //节点数目多于两个,并且p,q指针指向同一个节点 { if (position == 0) { q = q.Next; while (q.Next.Next != p) { q = q.Next; } DelData = q.Next.data; markNum = q.Next.mark; q.Next = q.Next.Next; } else { DelData = p.data; markNum = p.mark; while (q.Next != null && q.Next != p) { q = q.Next; } q.Next = p.Next; } } else { DelData = q.data; markNum = q.mark; p.Next = q.Next; } } else { DelData = q.data; markNum = q.mark; } #endregion nd = q.Next; Length--; Console.WriteLine("删除的节点的序号:{0}; 删除的节点的数据域的值:{1}", markNum, DelData.ToString()); //递归调用 DeleteElem(DelData, Length, nd); } } class Node//将节点的结构封装成一个类 { public int data;//数据域 public Node Next;//指针域 public int mark;//节点的标号(以节点入链表的顺序来标志) public Node(int val,int markVal)//声明一个新的节点 { data = val; Next = null; mark = markVal; } } }