DS博客作业02--线性表

0.PTA得分截图

1.本周学习总结

1.1总结线性表内容

顺序表结构体定义

#define MaxSize 50
typedef int ElemType;//ElemType类型实际上是int
typedef struct{
    ElemType data[MaxSize];//存放顺序表中的元素
    int length;//顺序表的长度
}SqList;

创建顺序表

void CreateList(SqList &L,int n){
int i;
L=new List;
L->length=n;
for(i=0;i<n;i++)
cin>>L->data[i];
}

销毁顺序表

void DestoryList(Sqlist *&L)
{
free(L);
);

顺序表插入

bool ListInsert(List &L, int i,ElemType e)
{
int j;
if (i<1|| i>L-> length+1)
return false; // 参数错误时返回false
i--;//将顺序表逻辑序号转化为物理序号
for (j=L->length;j>i;j--) //将data[i.. n]元素后移一个位置
L- >data[j]=L->data[j-1];
L->data[i]=e;//插入元素e .
L-> length++ ;//顺序表长度增1
return true;//成功插入返回true
}

顺序表删除

bool ListDelete(List &L,int i, ElemType &e)
{
if (i<1 || i>L->length) //删除位置不合法
return false;
i-- ;/ /将顺序表逻辑序号转化为物理序号
e=L->data[i] ;
for (int j=i;j<L->1ength-1;j++)
L->data[j]=L->data[j+1];
L->length--; / /顺序表长度减1
return true ;
}

链表的结构体定义

typedef struct LNode {
ElemType data;//数据域
struct LNode *next ;//指针域
} LNode, *LinkList;

头插法

void CreateListF(LinkList& L, int n)
{
	L = new LNode;
	int i = 1;
	L->next = NULL;
	LinkList p;
	for (i = 1; i <= n; i++)
	{
		p = new LNode;
		p->next=L->next;
		L->next = p;
		cin >> p->data;
	}
}

尾插法

void CreateListR(LinkList& L, int n)
{
	int i;
	LinkList node, tail;
	L = new LNode;
	L->next = NULL;
	tail = L;
	for (i = 1; i <= n; i++)
	{
		node = new LNode;
		cin >> node->data;
		node->next = NULL;
		tail->next = node;
		tail = node;
	}
}

链表插入

bool ListInsert(Linklist &L,int i,ElemType e){
int j=0;
LinkList p=L,s;
wile(p&&j<i-1){
j++;p=p->next;
}
if(p==NULL)return false;//未找到第i-1个节点
s=new LNode;
s->data=e;
s->next=p->next;//插在p后面
p->next=s;
return true;
}

链表删除

bool ListDelete_ L(LinkList &L,int i,ElemType &e)
{
int j=0;
LinkList p=L,s,q; 
while(p&&j<i-1){
p=p->next;j++;
}
if(p==NULL) return false;
q=p->next; //第i个位置
if(q==NULL) return false;
e=q->data;
p->next=q->next;//改变指针关系,删除
delete q;
return true;
}

有序单链表插入

void ListInsert(LinkNode &L,ElemType e)
{ LinkNode pre=L,p;
while (pre->next!=NULL && pre->next->data<e)
pre=pre->next; //查找插入结点的前驱结点*pre
p=new LinkNode;
p->data=e;//创建存放e的数据结点*p
p->next= pre->next; //在 *pre结点之后插入*p结点
pre->next=p;
}

有序单链表删除

void ListDelete(LinkList& L, ElemType e)
{
    LinkList pre=L;
    if (L->next == NULL) return;//空链
    while(pre->next)//寻找删除位置的前驱
    {
    if (pre->next->data == e)
    {
        pre->next = pre->next->next;
        return;
    }
    pre = pre->next;
    }
    cout << e << "找不到!"<< endl;

有序表合并

void MergeList(LinkList &L1,LinkList L2)
{
    LinkList p1,p2;
    LinkList tail;
    p1=L1->next;
    L1->next=NULL;
    p2=L2->next;
    tail=L1;
    while(p1&&p2)
    {
        if(p1->data<p2->data)
        {
            tail->next=p1;
            tail=p1;
            p1=p1->next;
        }
        else if(p2->data<p1->data)
        {
            tail->next=p2;
            tail=p2;
            p2=p2->next;
        }
        else
        {
            tail->next=p2;
            tail=p2;
            p1=p1->next;
            p2=p2->next;
        }
    }
    if(p1)tail->next=p1;
}

循环链表

1、从循环链表中的任何一个结点的位置都可以找到其他所有结点,而单链表做不到;
2.循环链表中没有明显的尾端,循环条件:
带头节点:p->next=L;
不带头节点:p!=L;

双链表

结构体定义:

typedef struct DNode//声明双链表节点类型
{ElemType data ; 
struct DNode *prior;//指向前驱节点
struct DNode *next;//指向后继节点
} DLinkList;

特点

双链表有点:
。从任一结点出发可以快速找到其前驱结点和后继结点:
。从任一结点出发可以访问其他结点。

1.2.谈谈你对线性表的认识及学习体会

对线性表的认识:链表(Linked List)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针。线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的。线性表的逻辑结构简单,便于实现和操作。因此,线性表这种数据结构在实际应用中是广泛采用的一种数据结构。
学习体会:线性表衔接了上学期所学的链表知识,但由于上学期链表学得也是懵懵懂懂,而且也没有做很多编程练习,所以刚开始学线性表的时候很困难。后来发现其实只要把图画出来,就相对好理解多了。做PTA时候碰到的一些问题,一般会求助于舍友,实在不明白就下载老师的PPT来再看一遍,把思路捋清楚。

2.PTA实验作业

2.1 6-2 jmu-ds-有序表插入数据

2.1.1 代码截图


2.1.2本题PTA提交列表说明


Q1: 部分正确
A1:我这种做法在插入位置是第一个和最后一个的时候需要单独拿出来考虑,一开始没有考虑到。
Q2:部分正确
A2:循环条件没有加i<=L->length导致错误。

2.2 6-3 jmu-ds- 顺序表删除重复元素

2.2.1 代码截图


2.2.2本题PTA提交列表说明


Q1:部分正确
A1:左移时k 应该length-1,一开始携程klength,但其实最后一个时无法再移的。
Q2:部分正确
A2:这种方法当删除到最后只剩下2个数据的时候,需要单独拿出来讨论,一开始没有考虑到。

2.3 6-8 jmu-ds-链表倒数第m个数

2.3.1 代码截图

2.3.2本题PTA提交列表说明


Q1:多种错误
A1:i++最初放在了if的后面,但因为int i=0,所以是不对的,若int i=1,放if后面就可以。

3.阅读代码

3.1 题目及解题代码



3.1.1该题的设计思路

假设有个圆形的操场,操场上有a和b两个人,a和b最开始的时候是站在一起的

假设b的速度是a的一倍,b不停的跑把a甩在身后了

b跑了N圈之后,终于追上a了

按照这个思路,我们可以假设有a和b两个指针,一个慢一个快,如果链表是有环状的,那么走的快的那个指针迟早会跟慢指针重合的

时间按复杂度O(n)

空间复杂度O(1)

3.1.2 该题的伪代码

定义两个快慢指针faster,slower
if(空链表)return false;end if
while(faster没跑完)
{faster一次跑2步;
 slower一次跑1步;
if(相遇)
return true//断定是环形链表
end if;
end while;
return false//否则则不是环形链表

3.1.3 运行结果

3.1.4分析该题目解题优势及难点。

改题目的解题优势就是使用了老师上课所提到的快慢指针。否则就要使用相对复杂的哈希表,如果使用哈希表的话,空间复杂度会达到O(n)。
难点:如果想到了用快慢指针的话编写起来就不会有太大难度,主要是能想到用快慢指针,将复杂的问题简单化了,很值得我的学习。

3.2题目及解题代码


3.2.1该题的设计思路

先求出链表长度size,若k取余size为空,那么不用旋转了,直接返回head;否则将链表首尾相连形成环形链表,由于k表示尾节点向右移动k%size位,那么头节点向右移动size-k%size位,此时的tail移动size-k%size位到达新头节点的前驱节点,我们仅仅需要保存新头节点,同时断开链表就好了。

时间按复杂度O(n)

空间复杂度O(1)

3.2.2该题的伪代码

if(空链或者不旋转)return head;
end if;
定义一个尾指针tail;
while(tail->next)
计算链表长度size;
tail=tail->next;
end while;
if(k%size==0)//相当于没旋转
return head;
end if;
tail->next=head;//形成环形链表,即循环链表;
int m=size-k%size;//tail实际移动m步;
while(m--)tail=tail->next;
 ListNode *res=tail->next;//定义旋转后链表的头节点res
        tail->next=nullptr;
        return res;

3.2.3 运行结果

3.2.4分析该题目解题优势及难点。

该题目的解题优势是在将链表转化为环形链表,即循环链表,这样题目就很容易理解并解答了。
难点:求出实际移动的步数m和变换环形链表。

posted @ 2020-03-08 21:00  王柏鸿  阅读(315)  评论(0编辑  收藏  举报