顺序表 顺序线性表 是指用一组地址连续的存储单元 一次存储数据元素的线性结构。
1 2 3 4 5 #define MAX_SIZE 1000 typedef struct { int data[MAX_SIZE]; int length; }SqList;
引用类型做参数传地址 1 2 3 4 5 6 void main () { int i = 1 ; int &j = i; i = 2 ; cont<<"i=" <<i<<"j=" <<j; }
事例中j是i的引用,代表i的一个替代名,i值改变时j也跟着改变
1 2 3 4 5 6 7 8 9 10 11 12 #include <iostream> using namespace std;void swap (int &m, int &n) { int temp = m; m = n; n = temp; } void main () { int a = 1 ,b = 2 ; swap (a,b); cout<<a<<endl<<b<<endl; }
与传递指针的效果一样
引用类型做形参,在内存中并没有产生实参的副本,直接对实参进行操作,因此使用引用传递参数的时间空间效率都很好
主要操作的实现 Insert 1 2 3 4 5 6 7 8 9 10 11 12 void Insert (SqList &L, int e, int n) { if (n < 0 || n > L.length) { return ; } else { for (int i=L.length-1 ; i>=n; i--) { L.data[i+1 ] = L.data[i]; } L.data[n] = e; } L.length++; }
Delete 1 2 3 4 5 6 7 8 9 10 void Delete (SqList &L, int n) { if (n < 0 || n >= L.length) { return ; } for (int i=n; i<L.length-1 ;i++) { L.data[i] = L.data[i+1 ]; } L.length--; }
总结 优点
缺点
在插入、删除时需要移动大量元素
浪费存储空间
属于静态存储形式,数据元素的个数不能自由扩充
链表 链表 用一组物理位置任意 的存储单元来存放线性表,链表中逻辑次序与物理次序不一定相同。
概念 链表 由若干个结点 构成,每一个结点包括数据域 与指针域 ,数据域存储数据本身,指针域存储下一个元素的地址,用来表示逻辑次序。只要记录第一个元素的指针(头指针 )即可找到其他元素的存储位置
单链表: 结点只有一个指针域的链表
双链表: 结点有两个指针域的链表,一个存储前驱的地址,一个存储后继的地址
循环链表: 首尾相接的链表为循环链表
头结点与首元结点
头结点是在链表的首元结点之前附设的一个结点
首元结点为存储第一个元素的结点
1 2 3 4 typedef struct Lnode { int data; Lnode *next; }Lnode, *LinkList;
定义链表L通常用LinkList L;,定义结点通常用Lnode *p;
对链表的操作 Init 链表初始化
1 2 3 4 5 void Init (LinkList &L) { L = new Lnode; L->data = 0 ; L->next = NULL ; }
Destory 销毁链表
1 2 3 4 5 6 7 void Destroy (LinkList &L) { while (L) { LinkList p = L; L = L->next; delete p; } }
GetData 获取第n位的数据
1 2 3 4 5 6 7 int GetData (LinkList &L, int n) { Lnode *p = L; for (int i=0 ;i<n;i++) { p = p->next; } return p->data; }
Search 查找链表中数据为e的结点的位置并返回
1 2 3 4 5 6 7 8 9 10 int Search (LinkList &L, int e) { Lnode *p = L->next; for (int i=1 ; i<=L->data; i++) { if (p->data == e) { return i; } p = p->next; } return 0 ; }
Insert 在链表的第n位插入新元素e
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void Insert (LinkList &L, int n, int e) { if (n < 1 || n > L->data + 1 ) { return ; } Lnode *p = L; Lnode *newdata = new Lnode; newdata->data = e; for (int i=1 ;i<n;i++) { p = p->next; } Lnode *q = p->next; p->next = newdata; newdata->next = q; L->data++; }
Delete 删除链表第n位的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 void Delete (LinkList &L, int n) { if (n < 1 || n > L->data) { return ; } Lnode *p = L; for (int i=1 ;i<n;i++) { p = p->next; } Lnode *q = p->next; p->next = q->next; delete q; L->data--; }
头插法建立单链表 将新建的结点接在头结点的后面
1 2 3 4 5 6 7 8 9 10 11 void Create (LinkList &L, int n) { L = new Lnode; L->data = n; L->next = NULL ; for (int i = 0 ; i < n; i++) { Lnode *p = new Lnode; cin >> p->data; p->next = L->next; L->next = p; } }
尾插法建立单链表 将新建的结点插在尾指针后
1 2 3 4 5 6 7 8 9 10 11 12 void Create (LinkList &L, int n) { L = new Lnode; L->data = n; L->next = NULL ; Lnode *r = L; for (int i = 0 ; i < n; i++) { Lnode *p = new Lnode; cin >> p->data; r->next = p; r = p; } }
循环链表 链表中最后一个结点的next指向头结点,由于表的操作通常是在首尾位置上执行,若用头指针表示单循环链表,查找最后一位元素时需要遍历整个链表,较为麻烦,但如果使用尾指针表示单循环链表,第一位元素可表示为R->next->next,最后一位为R,更为方便
循环链表的合并 1 2 3 4 5 6 7 8 LinkList Hebing (LinkList &R1, LinkList &R2) { Lnode *L1 = R1->next; Lnode *L2 = R2->next; R1->next = L2->next; R2->next = L1; delete L2; return R2; }
双向链表 双链表结点结构为
1 2 3 4 5 typedef struct Lnode { int data; Lnode *prior; Lnode *next; }Lnode, *LinkList;
Insert 双链表的插入操作,在第n位插入数据为e的结点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void Insert (LinkList &L, int n, int e) { if (n < 1 || n > L->data + 1 ) { return ; } Lnode *p = L; Lnode *newdata = new Lnode; newdata->data = e; for (int i = 1 ; i < n; i++) { p = p->next; } newdata->next = p->next; newdata->prior = p; p->next = newdata; if (newdata->next) newdata->next->prior = newdata; L->data++; }
Delete 双链表的删除操作,删除第n位的结点
1 2 3 4 5 6 7 8 9 10 11 12 13 void Delete (LinkList &L, int n) { if (n < 1 || n > L->data) { return ; } Lnode *p = L; for (int i=0 ;i<n;i++) { p = p->next; } p->prior->next = p->next; if (p->next) p->next->prior = p->prior; delete p; L->data--; }
总结 优点
结点空间可以动态申请与释放
元素间的逻辑次序靠指针表示,插入删除不需要移动元素
缺点
存储密度小,每个结点的指针域需额外占用存储空间,存储密度为 结点数据占用空间/结点占用总空间 ,指针通常为8字节,顺序表中存储密度为1
链式存储结构是非随机存取结构,操作时需要从头指针沿链查找该节点,增加了算法的复杂度