一,顺序表 1.1 顺序表的实现 静态实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #define MaxSize 10 typedef struct { int data[MaxSize]; int length; }SqList;void InitList (SqList &L) { L.length = 0 ; }int main () { SqList L; InitList (L); return 0 ; }
动态实现: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #define MaxSize 10 #define InitSize 10 typedef struct { int *data; int MaxSize; int length; }SeqList;void InitList (SqList &L) { L.data = (int *)malloc (InitSize * sizeof (int )); L.length = 0 ; L.MaxSize = InitSize; }void IncreaseSize (SqList &L, int len) { int *p = L.data; L.data = (int *)malloc ((L.MaxSize+len) * sizeof (int )); for (int i = 0 ; i < L.length; i++) L.data[i] = p[i]; L.MaxSize = L.MaxSize + len; free (p); }int main () { SeqList L; InitList (L); ... IncreaseSize (L, 5 ); return 0 ; }
malloc() 函数的作用:会申请一片存储空间,并返回存储空间第一个位置的地址,也就是该位置的指针。
1.2 顺序表的基本操作 插入: 1 2 3 4 5 6 7 8 9 10 11 12 bool ListInsert (SqList &L, int i, int e) { if (i < 1 || i > L.length+1 ) return false ; if (L.length >= MaxSize) return false ; for (int j = L.length; j >= i; j--) L.data[j] = L.data[j-1 ]; L.data[i-1 ] = e; L.length++; return true ; }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 删除: 1 2 3 4 5 6 7 8 9 10 bool ListDelete (SqList &L, int i, int &e) { if (i < 1 || i > L.length) return false ; e = L.data[i-1 ]; for (int j = i; j < L.length; j++) L.data[j-1 ] = L.data[j]; L.length--; return true ; }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 按位查找: 1 2 3 4 5 6 #define MaxSize 10 ElemType GetElem (SqList L, int i) { return L.data[i-1 ]; }
1 2 3 4 5 6 #define InitSize 10 ElemType GetElem (SeqList L, int i) { return L.data[i-1 ]; }
时间复杂度: O ( 1 )
按值查找: 1 2 3 4 5 6 7 int LocateElem (SqList L, ElemType e) { for (int i = 0 ; i < L.length; i++) if (L.data[i] == e) return i+1 ; return 0 ; }
在《数据结构》考研初试中,手写代码可以直接用“==”,无论 ElemType 是基本数据类型还是结构类型
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 二,单链表 2.1 单链表的实现 不带头结点的单链表: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;bool InitList (LinkList &L) { L = NULL ; return true ; }void test () { LinkList L; InitList (L); ... }bool Empty (LinkList L) { return (L==NULL ) }
带头结点的单链表: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;bool InitList (LinkList &L) { L = (LNode *)malloc (sizeof (LNode)); if (L == NULL ) return false ; L->next = NULL ; return true ; }void test () { LinkList L; InitList (L); ... }bool Empty (LinkList L) { if (L->next == NULL ) return true ; else return false ; }
2.2 单链表的建立 尾插法建立单链表: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 LinkList List_TailInsert (LinkList &L) { int x; L = (LinkList)malloc (sizeof (LNode)); LNode *s, *r = L; scanf ("%d" , &x); while (x!=9999 ){ s = (LNode *)malloc (sizeof (LNode)); s->data = x; r->next = s; r = s; scanf ("%d" , &x); } r->next = NULL ; return L; }
时间复杂度:O ( n )
头插法建立单链表: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 LinkList List_HeadInsert (LinkList &L) { LNode *s; int x; L = (LinkList)malloc (sizeof (LNode)); L->next = NULL ; scanf ("%d" , &x); while (x!=9999 ){ s = (LNode *)malloc (sizeof (LNode)); s->data = x; s->next = L->next; L->next = s; scanf ("%d" , &x); } return L; }
头插法实现链表的逆置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 LNode *Inverse (LNode *L) { LNode *p, *q; p = L->next; L->next = NULL ; while (p != NULL ){ q = p; p = p->next; q->next = L->next; L->next = q; } return L; }
2.3 单链表的基本操作 按位序插入(带头结点): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;bool ListInsert (LinkList &L, int i, ElemType e) { if (i<1 ) return False; LNode *p; int j=0 ; p = L; while (p!=NULL && j<i-1 ){ p = p->next; j++; } if (p==NULL ) return false ; LNode *s = (LNode *)malloc (sizeof (LNode)); s->data = e; s->next = p->next; p->next = s; return true ; }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 按位序插入(不带头结点): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;bool ListInsert (LinkList &L, int i, ElemType e) { if (i<1 ) return false ; if (i==1 ){ LNode *s = (LNode *)malloc (size of (LNode)); s->data =e; s->next =L; L=s; return true ; } LNode *p; int j=1 ; p = L; while (p!=NULL && j<i-1 ){ p = p->next; j++; } if (p==NULL ) return false ; LNode *s = (LNode *)malloc (sizeof (LNode)); s->data = e; s->next = p->next; p->next = s; return true ; }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 除非特别声明,否则之后的代码都默认为带头结点
指定结点的后插操作: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;bool InsertNextNode (LNode *p, ElemType e) { if (p==NULL ){ return false ; } LNode *s = (LNode *)malloc (sizeof (LNode)); if (s==NULL ) return false ; s->data = e; s->next = p->next; p->next = s; return true ; }bool ListInsert (LinkList &L, int i, ElemType e) { if (i<1 ) return False; LNode *p; int j=0 ; p = L; while (p!=NULL && j<i-1 ){ p = p->next; j++; } return InsertNextNode (p, e) }
时间复杂度:O ( 1 )
指定结点的前插操作: 如果传入头指针,就可以循环整个链表找到指定结点p的前驱结点q,再对q进行后插操作; 如果不传入头指针,可以在指定结点p后插入一个结点s,并交换两个结点所保存的数据,从而变相实现指定结点的前插操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;bool InsertPriorNode (LNode *p, ElemType e) { if (p==NULL ) return false ; LNode *s = (LNode *)malloc (sizeof (LNode)); if (s==NULL ) return false ; s->next = p->next; p->next = s; s->data = p->data; p->data = e; return true ; }
时间复杂度:O ( 1 )
按位序删除: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef struct LNode { ElemType data; struct LNode *next;}LNode, *LinkList;bool ListDelete (LinkList &L, int i, ElemType &e) { if (i<1 ) return false ; LNode *p; int j=0 ; p = L; while (p!=NULL && j<i-1 ){ p = p->next; j++; } if (p==NULL ) return false ; if (p->next == NULL ) return false ; LNode *q = p->next; e = q->data; p->next = q->next; free (q) return true ; }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 删除指定结点: 如果传入头指针,就可以循环整个链表找到指定结点p的前驱结点q,再对p进行删除操作; 如果不传入头指针,可以把指定结点p的后继结点q删除,并使结点p保存结点q存储的数据,从而变相实现删除指定结点的操作。但是如果指定结点p没有后继结点,这么做会报错 。
1 2 3 4 5 6 7 8 9 10 bool DeleteNode (LNode *p) { if (p==NULL ) return false ; LNode *q = p->next; p->data = q->data; p->next = q->next; free (q); return true ; }
时间复杂度:O ( 1 )
按位查找: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef struct LNode { ElemType data; struct LNode *next; }LNode, *LinkList;LNode * GetElem (LinkList L, int i) { if (i<0 ) return NULL ; LNode *p; int j=0 ; p = L; while (p!=NULL && j<i){ p = p->next; j++; } return p; }bool ListInsert (LinkList &L, int i, ElemType e) { if (i<1 ) return False; LNode *p = GetElem (L, i-1 ); return InsertNextNode (p, e) }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 按值查找: 1 2 3 4 5 6 7 8 9 LNode * LocateElem (LinkList L, ElemType e) { LNode *P = L->next; while (p!=NULL && p->data != e){ p = p->next; } return p; }
时间复杂度:
最好时间复杂度:O ( 1 ) 最坏时间复杂度:O ( n ) 平均时间复杂度:O ( n ) 计算单链表长度: 1 2 3 4 5 6 7 8 9 10 int Length (LinkList L) { int len=0 ; LNode *p = L; while (p->next != NULL ){ p = p->next; len++; } return len; }
时间复杂度:O ( n )
三,双链表
双链表的初始化 (带头结点) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 typedef struct DNode { ElemType data; struct DNode *prior, *next; }DNode, *DLinklist;bool InitDLinkList (Dlinklist &L) { L = (DNode *)malloc (sizeof (DNode)); if (L==NULL ) return false ; L->prior = NULL ; L->next = NULL ; return true ; }void testDLinkList () { DLinklist L; InitDLinkList (L); ... }bool Empty (DLinklist L) { if (L->next == NULL ) return true ; else return false ; }
双链表的后插操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typedef struct DNode { ElemType data; struct DNode *prior, *next; }DNode, *DLinklist;bool InsertNextDNode (DNode *p, DNode *s) { if (p==NULL || s==NULL ) return false ; s->next = p->next; if (p->next != NULL ) p->next->prior = s; s->prior = p; p->next = s; return true ; }
双链表的前插操作、按位序插入操作都可以转换成后插操作
双链表的删除操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 bool DeletNextDNode (DNode *p) { if (p==NULL ) return false ; DNode *q =p->next; if (q==NULL ) return false ; p->next = q->next; if (q->next != NULL ) q->next->prior=p; free (q); return true ; }bool DestoryList (DLinklist &L) { while (L->next != NULL ){ DeletNextDNode (L); free (L); L=NULL ; } }
双链表的遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 while (p!=NULL ){ p = p->next; }while (p!=NULL ){ p = p->prior; }while (p->prior!=NULL ){ p = p->prior; }
双链表不可随机存取,按位查找、按值查找操作都只能用遍历的方式实现。
四,循环链表
循环单链表的实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 typedef struct LNode { ElemType data; struct LNode *next; }DNode, *Linklist;bool InitList (LinkList &L) { L = (LNode *)malloc (sizeof (LNode)); if (L==NULL ) return false ; L->next = L; return true ; }bool Empty (LinkList L) { if (L->next == L) return true ; else return false ; }bool isTail (LinkList L, LNode *p) { if (p->next == L) return true ; else return false ; }
循环双链表的实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 typedef struct DNode { ElemType data; struct DNode *prior, *next; }DNode, *DLinklist;bool InitDLinkList (DLinklist &L) { L = (DNode *) malloc (sizeof (DNode)); if (L==NULL ) return false ; L->prior = L; L->next = L; }bool Empty (DLinklist L) { if (L->next == L) return true ; else return false ; }bool isTail (DLinklist L, DNode *p) { if (p->next == L) return true ; else return false ; }
循环双链表的插入和删除操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 bool InsertNextDNode (DNode *p, DNode *s) { s->next = p->next; p->next->prior = s; s->prior = p; p->next = s; }bool DeletNextDNode (DNode *p) { DNode *q =p->next; p->next = q->next; q->next->prior=p; free (q); return true ; }
参考自:https://blog.csdn.net/qq_55593227/article/details/123598044