线性表

  • 1.逻辑结构
  • 2.存储结构
    • 2.1顺序存储
    • 2.2链式存储
  • 3.线性表的实现
    • 3.1 顺序存储结构实现
    • 3.2顺序存储操作实现
    • 3.3链式存储结构实现(单链表)
    • 3.4链式存储操作实现(单链表)
    • 3.5 线性表实现-静态链表
    • 3.6线性表实现-循环链表
    • 3.7线性表实现-双链表
    • 3.8循环双链表
  • 4. 总结与分析
  • 5.习题

(本文以及接下来的每一篇都是这样的结构,先说逻辑结构,然后初步认识物理结构,然后实现代码,最后结合代码重新认识物理结构的优缺点,本章的代码与习题代码都打包成了文件: 线性表及习题代码)

1.逻辑结构

  1. 线性表:零个或多个相同数据类型的数据元素的有限序列。

(元素之间是有顺序的。第一个元素无前驱,最后一个元素无后继,其他元素都有且只有一个前驱和一个后继。)

  1. 空表:线性表元素的个数n定义为线性表的长度,当n=0时,称为空表
  2. 在较为复杂的线性表中,数据元素可以由多个数据项组成。

(线性表是一种逻辑结构,它的物理结构可以用顺序表或链表实现,不要混淆线性表和顺序表)

2.存储结构

(存储结构结合第三节代码实现来看)

2.1顺序存储

  1. 线性表的顺序存储结构,指的是用一段地址连续的存储单元一次存储线性表的数据元素。

(线性表顺序存储时逻辑顺序和物理顺序相同)

  1. 顺序表存储结构是一种随机存取的存储结构,因为每一种元素所占的字节是相同的,很容易对任意一个位置的元素进行操作。
  2. 基本结构:类似于数组。

2.2链式存储

  1. 链式存储:用一组任意的存储单元存储线性表的数据元素,对于数据元素ai除了存储了数据元素信息,还存储了后继位置(也就是指针)。

  2. 基本结构:链表由n个节点组成,每一个节点有一个数据域存储元素的值,还有一个指针域,存储该元素后继的地址也就是指针。指向第一个节点位置的指针我们称为头指针,最后一个节点的指针指向NULL。(初级的单链表结构)

  1. 头节点结构:在列表的第一个节点前我们增加一个头节点,头节点的数据域存储链表的元素个数或者不存储任何信息,指针域存储第一个节点的位置,此时的头指针指向头节点。这样的结构更加规范,至于为什么大家在代码中体会,以后的学习中链表通常都会有头节点。

3.线性表的实现

3.1 顺序存储结构实现

3.1.1 静态分配

#define MaxSize 50
typedef int ElemType;
//ElemType可以是任何数据类型,为举例方便此处设为int
typedef struct {ElemType data[MaxSize];//存储元素的数组int length;//记录元素个数
}SqList;

静态分配方便大家了解线性表的顺序存储结构实现,但是当我们的元素个数超过MaxSize时会发生数据溢出。

3.1.2 动态分配

#define InitSize 50
#define IncreaseSize 10 //容量不足时一次增加的容量
typedef int ElemType;typedef struct {ElemType *data;int MaxSize, length;//length记录元素个数,MaxSize是当前线性表容量。length<=MaxSize
}SqList;

动态分配在容量不足时会扩容,所以接下来的线性表操作都是以动态分配的顺序存储结构为基础。

3.2顺序存储操作实现

(前言:关于SqList &L,表示引用的意思,L的类型是SqList, 如果在函数里L的值被改变,主函数里L的值也会变的)

(SqList L,传参,L的类型是SqList, L的值的改变并不会影响主函数中的L,但是L->data的值改变了,原函数L->data的值也会变的)

(SqList *L,这里的L是一个地址,改变L的值并不会影响主函数的值,但是L->data的值改变了,原函数L->data的值也会变的,其实就是对参数的改变不会影响主函数,但是对一些地址存储的值的改变是会影响主函数的。大家自己实验理解好方便我们实现操作)

#define InitSize 50
#define IncreaseSize 10
#define OK 1            //为了方便函数编写,表示操作成功
typedef int Status;     //Status是函数返回值类型,可以是任何类型,此处用int
typedef int ElemType;typedef struct {ElemType *data;int MaxSize, length;
}SqList;

3.2.1 初始化线性表

/*
获得一个线性表
*/
Status InitSqList(SqList& L) {L.data = (ElemType*)malloc(sizeof(ElemType)*InitSize); //分配初始内存if (!L.data)                   //若分配失败则结束程序return ERROR;L.MaxSize = InitSize;            //容量赋值L.length = 0;                    //元素赋值return OK;
}
int main() {SqList L ;int x = InitSqList(L);cout << x << endl;             //打印结果为1
}

3.2.2 插入元素

Status ListInsert(SqList& L, int i, ElemType e) {if (i < 1 || i > L.length + 1)return ERROR;              //插入元素的位置要合法,i=1时插入在最前面,i=length+1时插入在末尾if (L.length >= L.MaxSize) {   //容量不足//重新分配内存L.data = (ElemType*)realloc(L.data, sizeof(ElemType) * (L.MaxSize + IncreaseSize));if (!L.data) return ERROR;L.MaxSize = L.MaxSize + IncreaseSize;}for (int j = L.length; j >= i; j++) {//第i个位置及之后的位置的元素都向后挪动一个元素的位置L.data[j] = L.data[j - 1];}L.data[i - 1] = e;                //第i个位置的索引是i-1L.length++;return OK;
}

为了验证我们写的对不对,我们写一个打印线性表的函数

Status ListPrint(SqList L) {for (int i = 0; i < L.length; i++) {cout << L.data[i] << "";cout << "\t" << "";}cout << "" << endl;return OK;
}

然后调用函数

int main() {SqList L ;int x = InitSqList(L);for (int i = 0; i < 55; i++) {ListInsert(L, i + 1, i + 1);}ListPrint(L);//打印出1 2 3...55 说明函数写对了
}

3.2.2删除操作

/*
删除i位置元素
*/
Status ListDelete(SqList& L, int i) {if (i < 1 || i > L.length) //位置不合法return ERROR;for (int j = i; j < L.length; j++) {//第i+1位置和之后的都向前挪动一个元素的位置L.data[j - 1] = L.data[j];}L.length--;return OK;
}

同时验证一下

int main() {SqList L ;int x = InitSqList(L);for (int i = 0; i < 55; i++) {ListInsert(L, i + 1, i + 1);}ListPrint(L);ListDelete(L,30);//删除第30个位置的元素ListPrint(L);//打印结果1 2 ...29 31 ... 55
}

3.3.2 按值查找

int GetElem(SqList L, ElemType e) {for (int i = 0; i < L.length; i++) {if (L.data[i] == e) {return i;}}return -1;//表示没有找到
}

检查一下

int main() {SqList L ;int x = InitSqList(L);for (int i = 0; i < 55; i++) {ListInsert(L, i + 1, i + 1);}ListPrint(L);ListDelete(L,30);ListPrint(L);cout << GetElem(L, 30) << endl; //打印-1cout << GetElem(L, 29) << endl; //打印28 说明写对了
}

顺序存储的其他操作都很简单了,接下来大家可以自行试着实现能想到的所有操作。

3.3链式存储结构实现(单链表)

(前言:本小节LinkList L是一个LNode* 类型,是地址,建立链表函数中我们需要改变L的值,所以应该是LinkList &L)

typedef struct LNode {ElemType data;struct LNode* next;
}LNode,* LinkList;          //LNode是节点,LinkList是头指针。
//相当于 typedef int* LinkList 此时LinkList是指向int数据的指针,上面只不过把int换成LNode

3.4链式存储操作实现(单链表)

3.4.1 头插法建立单链表:就是添加元素时添加在链表头。

/*
头插法建立单链表
*/
Status List_HeadInsert(LinkList &L){LNode* s=NULL;int e=9999;L = (LNode*)malloc(sizeof(LNode));//创建头节点,头指针L指向头节点。if (!L) return ERROR;L->next = NULL;cin >> e ;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));//s是新的节点if (!s) return ERROR;s->data = e;s->next = L->next;//s节点指向之前的节点L->next = s;      //s始终插入到L后面cin >> e;}return OK;
}

同样的,为了验证我们写一段打印线性表的代码

/*
打印链表
*/
Status ListPrint(LinkList L) {LinkList p = L->next;             //获得头节点while (p!= NULL) {cout << p->data ;cout << "\t";p = p->next;}cout << "\t" << endl;return OK;
}
int main() {LinkList L;List_HeadInsert(L);ListPrint(L);
}

打印结果如下图:

3.4.2 尾插法建立单链表:添加元素时添加在链表尾

/*
尾插法建立单链表
*/
Status List_TailInsert(LinkList& L) {LNode* s = NULL;LNode* r = NULL;int e = 9999;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->data = NULL;r = L;             //尾插法需要用到r来辅助cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));//s为新的节点s->data = e;s->next = NULL;r->next = s;  r = s;         //r始终为链表最后一个节点cin >> e;}return OK;
}
int main() {LinkList L;//List_HeadInsert(L);List_TailInsert(L);ListPrint(L);
}

打印结果如下:

3.4.3 按位置查找节点(按位置查找结点同理,大家可以自己试一下)

/*
获得第i个位置节点的地址
*/
LNode* GetElme(LinkList L, int i) {LNode *p = L->next;if (i < 1) return ERROR;i--;while (i > 0 && p!= NULL) {p = p->next;i--;}return p;
}
int main() {LinkList L;//List_HeadInsert(L);List_TailInsert(L);ListPrint(L);if(GetElme(L, 1)!=NULL)cout << GetElme(L, 1)->data << endl;if(GetElme(L, 5)==NULL)cout << ERROR << endl;
}

打印结果:

3.4.4 在第i个位置插入元素

/*
在第i个位置插入元素e
*/
Status LinkListInsert(LinkList L, int i, ElemType e) {LNode* r = NULL;LNode* s = NULL;if (i == 1) r = L;else r = GetElme(L, i-1); //获得第i个位置的前一个节点if (r == NULL)return ERROR;        //若前一个节点为NULL则i不合法s = (LNode*)malloc(sizeof(LNode));if (!s) return ERROR;/*在节点i-1后插入节点*/s->data = e;s->next = r->next;r->next = s;return OK;
}
int main() {LinkList L;//List_HeadInsert(L);List_TailInsert(L);ListPrint(L);ElemType e = 9999;cin >> e;LinkListInsert(L, 3, e);ListPrint(L);
}

打印结果如下:其他比如在某个节点前插入等方法大家可以自己试一下。

3.4.5 删除节点

/*
删除节点i
*/
Status LinkListDelete(LinkList L, int i) {LNode* r = NULL;LNode* s = NULL;if (i == 1)r = L;else r = GetElme(L, i - 1);if (r == NULL) return ERROR;if (r->next == NULL) return ERROR;s = r->next;   r->next = s->next;free(s);return OK;
}
int main() {LinkList L;//List_HeadInsert(L);List_TailInsert(L);ListPrint(L);LinkListDelete(L, 3);ListPrint(L);}

打印结果:

3.5 线性表实现-静态链表

3.5.1 静态链表的物理结构

typedef struct{ElemType data;int cur;
}SLinkList[MaxSize];

使用数组来实现链表的功能,数组元素有一个数据域和一个指针域,指针域的值并不是地址,而是下一个数组元素的索引。

实际上并没有链表方便,但是有一些高级语言并不支持指针,这是一种实现链表的巧妙的方法,大家学习这种思想就好了。大家如果学习过操作系统,也会很熟悉这种思想。关于它的操作代码就略过了,不重要。

3.6线性表实现-循环链表

3.6.1循环链表的物理结构:我们将链表最后一个节点的next由NULL改为头节点,那么整个链表就变成了一个圈。

typedef struct LNode {ElemType data;struct LNode* next;
}LNode, * LinkList;

发现了吧,和普通单链表一模一样。其实就是在创建链表的时候有区别,我们把头插法和尾插法代码写一下如下:

3.7.2 头插法建立循环链表:和普通单链表只差了注释的那一行,其他部分一模一样

Status RLinkList_HeadInsert(RLinkList& L) {int e = 9999;LNode* s = NULL;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->next =L;        //没有元素时头节点自己指向自己而非NULL cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));if (!s) return ERROR;s->data = e;s->next = L->next;L->next = s;cin >> e;}return OK;
}

3.7.3 尾插法建立循环链表:同样只差一行

Status RLinkList_TailInsert(RLinkList& L) {int e = 9999;LNode* s = NULL;LNode* r = NULL;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->next = L;  //没有元素时头节点自己指向自己而非NULL r = L;cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));if (!s) return ERROR;s->data = e;s->next = r->next;r->next = s;r = s;cin >> e;}return OK;
}

为了验证同样要写个打印双链表的。

Status RLinkListPrint(RLinkList L) {LNode* p = L->next;while (p != L) { //循环结束条件变了cout << p->data;cout << "\t";p = p->next;}cout << "\t" << endl;return OK;
}

我们来试一下:

int main() {RLinkList L1 = NULL, L2 = NULL;cout << "头插法:" << endl;RLinkList_HeadInsert(L1);RLinkListPrint(L1);cout << "尾插法:" << endl;RLinkList_TailInsert(L2);RLinkListPrint(L2);
}

打印结果如下:

其他的插入删除等方法和单链表一模一样,甚至把LinkList改为RLinkList就可以直接用了,此处略过。

3.7线性表实现-双链表

3.7.1 双链表的物理结构:单链表是指单向,我们只能从链表头查单链表尾,如果我们想从链表尾查到链表头那再加一条链子吧!

typedef struct LNode {ElemType data;struct LNode* next;//后继指针struct LNode* prior;//前驱指针
}LNode, * DLinkList;

3.7.2 头插法 尾插法 建立双链表:

Status DLinkList_HeadInsert(DLinkList &L){int e = 9999;LNode* s = NULL;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->next = NULL;L->prior = NULL; //多一个“链子” 比单链表多的步骤cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));s->data = e;L->next->prior = s; //后继节点的前驱指向s节点 比单链表多的步骤s->next = L->next; //s的后继指向其后继节点s->prior = L;      //s的前驱指向L节点       比单链表多的步骤L->next = s;      //L的后继指向s节点cin >> e;}return OK;
}
Status DLinkList_TailInser(DLinkList& L) {int e = 9999;LNode* s = NULL;LNode* r = NULL;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->next = NULL;L->prior = NULL; //多一个“链子” 比单链表多的步骤r = L;cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));s->data = e;L->next->prior = s; //后继节点的前驱指向s节点 比单链表多的步骤s->next = L->next;    //s的后继指向其后继节点s->prior = L;      //s的前驱指向L节点       比单链表多的步骤L->next = s;      //L的后继指向s节点r = s;cin >> e;}return OK;
}

写一个打印函数。这个打印函数可以正反双向打印哦!

Status ListPrint(DLinkList L, int reverse = 0) {DLinkList p = L->next;              //获得头节点if (reverse == 1) {                    //反向打印while (p->next != NULL)p = p->next;while (p != L) {cout << p->data;cout << "\t";p = p->prior;}}//ifelse {while (p != NULL) {cout << p->data;cout << "\t";p = p->next;}}//elesecout << "\t" << endl;return OK;
}

然后我们来验证一下:

int main() {DLinkList L1 = NULL, L2 = NULL;cout << "头插法建立链表L1" << endl;DLinkList_HeadInsert(L1);cout << "正向打印L1" << endl;ListPrint(L1);//默认是0 正向打印cout << "逆向打印L1" << endl;ListPrint(L1, 1);cout << "尾插法建立链表L2" << endl;DLinkList_TailInsert(L2);cout << "正向打印L2" << endl;ListPrint(L2);//默认是0 正向打印cout << "逆向打印L2" << endl;ListPrint(L2, 1);
}

打印结果如下:

3.7.3 按位置取值操作

LNode* GetElem(DLinkList L, int i, int reverse = 0) {if (i < 1) return NULL;LNode*  p = L->next;i--;if (reverse != 1) {while (i > 0 && p != NULL) {p = p->next;i--;}//while}//ifelse {while (p->next != NULL && p != NULL)//寻找最后一个节点p = p->next;while (i > 0 && p != L) {p = p->prior;i--;}}return p;
}
int main() {DLinkList L1 = NULL;DLinkList_TailInsert(L1);cout << GetElem(L1, 3)->data << endl;cout << GetElem(L1, 3,1)->data << endl;}

打印结果如图:

3.7.4 插入操作

单链表在插入节点时都要先找到该节点的前驱,然后向后插入。双链表直接找到i插入到它前面就好了。

Status DLinkListInser(DLinkList L, int i, ElemType e) {LNode* l = GetElem(L, i);if (!l) return ERROR;LNode* s = (LNode*)malloc(sizeof(LNode));s->data = e;s->next = l;s->prior = l->prior;l->prior->next = s;l->prior = s;return OK;
}

然后我们验证一下:

int main() {DLinkList L1 = NULL, L2 = NULL;DLinkList_TailInsert(L1);ListPrint(L1);DLinkListInser(L1, 3, 520);ListPrint(L1);}

打印结果如下:

3.7.5 删除元素

Status DLinkListDelete(DLinkList L, int i) {LNode* l = GetElem(L, i);if (!l) return ERROR;l->prior->next = l->next;if (l->next != NULL)l->next->prior = l;return OK;
}

我们验证一下:

int main() {DLinkList L1 = NULL, L2 = NULL;DLinkList_TailInsert(L1);DLinkListDelete(L1, 3);ListPrint(L1);
}

打印结果:

3.8循环双链表

3.8.1 物理结构 头节点的前驱指向尾节点,尾节点的后继指向头节点。

typedef struct LNode {ElemType data;struct LNode* next;struct LNode* prior;
}LNode, * RDLinkList;

代码是一样的,不过它叫RDLinkList,至于为什么不是DRLinkList,因为我喜欢呀!而头插法和尾插法也和双链表只差了两行:

Status RDLinkList_HeadInsert(RDLinkList& L) {int e = 9999;LNode* s = NULL;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->next = L; //与双向链表只差这一行L->prior = L;   //与双向链表只差这一行cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));s->data = e;if (L->next != NULL) //插入第一个节点时没有后继节点L->next->prior = s;s->next = L->next;  //s的后继指向其后继节点s->prior = L;      //s的前驱指向L节点       比单链表多的步骤L->next = s;      //L的后继指向s节点cin >> e;}return OK;
}Status DLinkList_TailInsert(RDLinkList& L) {int e = 9999;LNode* s = NULL;LNode* r = NULL;L = (LNode*)malloc(sizeof(LNode));if (!L) return ERROR;L->next = L;//与双向链表只差这一行L->prior = L; //与双向链表只差这一行r = L;cin >> e;while (e != 9999) {s = (LNode*)malloc(sizeof(LNode));s->data = e;//尾插法后面无节点          s->next = r->next;   //s的后继指向其后继节点s->prior = r;      //s的前驱指向L节点       比单链表多的步骤r->next = s;      //L的后继指向s节点r = s;cin >> e;}return OK;
}

我们来写一个不一样的打印函数,他会正向打印或逆向打印n个节点。

其他操作与双向链表一模一样。代码实现就到此结束了。

4. 总结与分析

4.1顺序表与链表的比较

存取方式:顺序表可以随机存取,链表只能从头顺序存取元素。

逻辑结构与物理结构:采用顺序存储时逻辑上相邻的元素物理上也是相邻的,采用链式存储时逻辑上相邻的元素物理上不一定相邻。

查找、删除与插入操作:若按位置查找,顺序表时间复杂度=O(1),链表=O(n)。

空间分配:顺序表静态分配时容易发生溢出,分配过大也可能浪费空间,不好掌握分配值大小。顺序表动态分配时,每次重新分配都需要移动元素位置,因为原来连续的空间未必满足重新分配空间的大小,操作效率低。链表的空间分配非常简单、灵活。

4.2 选择哪种物理结构?

基于存储的考虑:难以估计线性表的存储规模的时候,应选择链表。

基于运算的考虑:若查找频繁,顺序表是一个好的选择。若插入、删除频繁,链表是一个好的选择。

基于环境的考虑:有些语音并没有指针,容不得我们选择链表。

总结来说,稳定的线性表选择顺序存储,频繁插入、删除的线性表选择链式存储。

5.习题

(习题答案在:线性表及习题代码)

习题1.

已知一个带有头节点的单链表,假设该链表只给出了头指针list,在不改变链表的前提下。请设计一个尽可能高校的算法,查找链表中导数第k个位置的节点,k为整数。若查找成功算法输出该节点data域的值并返回1,否则只返回0。

习题2.

这个题目如果用普通的选择排序思想很容易但是时间复杂第为O(n^2)。所以要想出一个时间复杂度更小的。提醒:和习题1思想一样。

习题3.

提示:普通方法都要O(n^2).所以想一个O(n)算法吧,可以考虑用空间换时间。

习题4.

链表原地逆置,对于带头结点的链表L,设计一个空间复杂度为O(1),也就是不借助辅助空间,将单链表中元素逆置。

习题5.

线性表L=(a1,a2,…,an),我们设计一个空间复杂度为O(1)的算法,将线性表L变为L=(a1,an,a2,an-1,…)。

我们的答案时间复杂度未O(n),不要超过了。

系统掌握数据结构3线性表C++实现相关推荐

  1. python线性表和队列_[笔记]python数据结构之线性表:linkedlist链表,stack栈,queue队列...

    python数据结构之线性表 python内置了很多高级数据结构,list,dict,tuple,string,set等,在使用的时候十分舒心.但是,如果从一个初学者的角度利用python学习数据结构 ...

  2. c语言用两个栈构造队列伪码,数据结构习题线性表栈队列.doc

    数据结构习题线性表栈队列 线性表(58) 1. 在单链表.双链表和单循环链表中,若仅知道指针p指向某结点,不知道头指针,能否将结点*p从相应的链表中删去?若可以,其时间复杂度各为多少? 2.设线性表的 ...

  3. 【Java数据结构】线性表

    线性表 线性表是最基本.最简单.也是最常用的一种数据结构. 线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而 ...

  4. step3 . day2 数据结构之线性表链表

    今天继续学习数据结构的线性表部分,从基础的顺序表到链表,类比写了一些调用函数,完成了表的增删改查排序等问题. 尤其是链表的排序,费了很大的心思终于捋顺写出来了,小有成就感,而且代码一次通过率越来越高, ...

  5. 数据结构之线性表(附代码)

    数据结构 之 线性表(附代码) 线性表思维导图: 线性表定义(逻辑结构): 一.顺序表 1.顺序表思维导图: 2.顺序表的逻辑结构: 3.顺序表基本操作的功能实现: 1.线性表的静态定义: 2.线性表 ...

  6. 数据结构之线性表的基本C语言语法

    一开始没做笔记,大家想看的话可以参考这里 [数据结构绪论] [数据结构(二)] [数据结构--算法和算法分析] [数据结构--渐进时间复杂度] [数据结构--初识线性表] [数据结构--线性表的顺序实 ...

  7. 用Java描述数据结构之线性表的链式存储(链表),模拟LinkedList实现

    上一篇介绍了顺序表:用Java描述数据结构之线性表的顺序存储(顺序表),ArrayList及其方法的介绍 上一篇博客中说明了什么是线性表--线性表就是一个个数据元素逻辑上以一对一的相邻关系(但是在物理 ...

  8. 用Java描述数据结构之线性表的顺序存储(顺序表),ArrayList及其方法的介绍

    我们先来想一想什么是线性表? 线性表是最基本.最简单.也是最常用的一种数据结构.线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列. 线性表中数据元素之 ...

  9. c语言如何删除数组中的某一个元素_数据结构之线性表高效删除重复元素

    刚刚学完数据结构之线性表中关于顺序表和单链表的知识,我们知道顺序表中存储数据的结构是一个数组,对于数组来说,在尾部插入.删除元素是比较高效的,但是如果在中间或者开头插入.删除元素,就会涉及数据的搬移, ...

最新文章

  1. 英国JIC院士组3.8万英镑招博后-植物代谢物与微生物组-截止6月27日
  2. 网站访问慢解决思路详细图解
  3. CAS实现单点登录(SSO)经典完整教程
  4. java import自定义类_Java实现的自定义类加载器示例
  5. nodejs和python和php_PHP和Nodejs能配合使用吗?
  6. Linux(CentOS)挂载NTFS格式的U盘、移动硬盘
  7. Git:错误:error:src refspec master does not match any
  8. 错误记录(二)java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I错误时的原因及解决办法
  9. matlab定义和调用函数m,Matlab学习-自定义函数与调用
  10. 用傅里叶分析得到频域信息 MATLAB,信号分析实验_傅里叶matlab实现.doc
  11. java接口 抽象类_关于JAVA接口和抽象类
  12. 软件设计模式与体系结构(入门基础知识)
  13. 人人都可以做深度学习应用:入门篇(下)
  14. python人机交互界面设计_Python-Tkinter图形化界面设计(详细教程 )
  15. 微软邮箱服务器出问题了,在微软邮箱登录时常见的问题有哪些
  16. 标签助手(TagHelper)
  17. 【百问网】物联网项目学习总结
  18. CTF 实验吧 天网管理系统
  19. 苹果手机怎么在照片上添加文字_手机上照片怎么制作视频
  20. python进阶必读汇总

热门文章

  1. 在线预览文档--微软的预览接口
  2. 如何在Android中使用emojicon库集成表情符号, 妈妈在也不用担心我的表情了~~~
  3. 面经 - Java 基础面试题
  4. postgres--流复制
  5. vue的lazy修饰符和number修饰符 、表单结构
  6. Nginx 深入浅出
  7. Unity ML-Agent 训练工业机械臂到达目标点 数字孪生
  8. android activity管理机制,使用弱引用的activity栈管理机制
  9. 蓝桥杯C/C++VIP试题每日一练之高精度加法
  10. 【LOJ3047】「ZJOI2019」浙江省选