Postgraduate entrance examination | Data structure [Chapter 2] Linear table
Article Directory
I. Linear table
- definition:A linear table is n ( n ≥ 0 ) n\ (n\geq0) of the same data typen (n≥0 ) a finite array of data elements, wherennn is the table length
- Basic operation:
InitList(&L): 初始化表. 构造一个空的线性表L, 分配内存空间 DestroyList(&L): 销毁表并释放线性表L所占用的内存空间. --- ListInsert(&L, i, e): 插入操作. 在表L中第i个位置插入指定元素e. ListDelete(&L, i, &e): 删除操作. 删除表L中第i个元素, 并用参数e返回删除元素的值. --- LocateElem(L, e): 按值查找 GetElem(L, i): 按位查找, 获取表L中第i个位置的元素的值 --- Length(L): 求表长 PrintList(L): 从前到后输出线性表L中所有元素 Empty(L): 判空操作
II. Sequence table
a. Definition
- definition:Use sequential storage to realize sequential storage of linear tables. Store logically adjacent elements in storage units that are also physically adjacent.
- Static allocation:
#include <stdio.h> #define MaxSize 10 typedef struct { int data[MaxSize]; int length; }SqList; void InitList(SqList &L) { for(int i=0; i<MaxSize; i++) L.data[i] = 0; L.Length = 0; } int main() { SqList L; InitList(L); ... return 0; }
- Dynamic allocation:
// 定义动态顺序表 typedef struct { int *data; int maxSize; int lenght; }seqDList; // 初始化动态顺序表 void initDList(seqDList &L) { L.data = (int *)malloc(MaxSize*sizeof(int)); L.maxSize = dftMaxSize; L.lenght = 0; } // 扩充动态顺序表 void increaseDList(seqDList &L, int len) { int* p = L.data; L.data = (int *)malloc((L.maxSize+len)*sizeof(int)); for (int i=0; i<L.lenght; i++) { L.data[i] = p[i]; } L.maxSize = L.maxSize + len; free(p); }
- Features:
- Random access, time complexity O ( 1 ) O(1)O(1)
- High storage density, each node only stores data elements
- Inconvenient to expand
- Insertion and deletion operations are inconvenient, and a large number of elements need to be moved
b. Insertion and deletion
- insert:
Time Complexity: Best O ( 1 ) O(1)O ( 1 ) , maximumO ( n ) O(n)O ( n ) , averageO ( n ) O(n)O ( n )// 在第i位插入元素 bool insertSList(seqSList &L, int i, int e) { if (i<1 || i>L.length+1) return false; if (L.length >= dftMaxSize) 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; }
- delete:
Time Complexity: Best O ( 1 ) O(1)O ( 1 ) , maximumO ( n ) O(n)O ( n ) , averageO ( n ) O(n)O ( n )// 删除第i位元素 bool deleteSList(seqSList &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]; return true; }
c. Find
- Bitwise lookup:
Time complexity O ( 1 ) O(1)O(1)// 按位查找 int GetElem(seqSList &L, int i) { return L.data[i-1] }
- Find by value:
Time Complexity: Best O ( 1 ) O(1)O ( 1 ) , maximumO ( n ) O(n)O ( n ) , averageO ( n ) O(n)O ( n )// 按值查找 int LocateElem(seqSList &L, int e) { for (int i=0; i<L.length; i++) if (L.data[i]==e) return i+1; return 0; }
III. Singly linked list
a. Definition
A linear list stored in a linked storage structure is called a singly linked list.
- Establishment and initialization of the lead node
typedef struct LNode { int data; struct LNode *next; }LNode, *linkList; // 带头结点初始化和判空 bool initList_h(linkList &L) { if (L==NULL) return false; L->next = NULL; return true; } bool empty_h(linkList &L) { if (L->next == NULL) return true; else return false; }
- Creation and initialization of unleaded nodes
// 不带头节点初始化和判空 bool initList(linkList &L) { L->next = NULL; return true; } bool empty(linkList L) { return L==NULL; }
b. to insert
- Bitwise insertion of leading node:Time complexity O ( n ) O(n)O ( n )
// 带头结点按位序插入 bool listInsert(linkList &L, int i, int e) { if (i < 1) // i 代表的是第i个结点 return false; LNode *p; int j = 0; p = L; while (p!=NULL && j<i-1) { // 令p指到第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; }
- bitwise insertion without a head node: time complexity O ( n ) O(n)O ( n )
// 不带头节点按位序插入 bool listInsert(linkList &L, int i, int e) { if (i < 1) return false; if (i == 1) { LNode *s = (LNode *)malloc(sizeof(LNode)); s->data = e; s->next = L; L = s; return true; } LNode *p = L; int j = 1; 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; }
- The post-insertion operation of the specified node:Time complexity O ( 1 ) O(1)O(1)
// 指定节点的后插操作 bool inserNextNode(LNode *p, int 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; }
- The forward insertion operation of the specified node:Time complexity bit O ( 1 ) O(1)The O ( 1 ) version
is essentially a back-interpolation method, but it just inserts a new node intoppAfter p , then make the data of the new node equal to ppThe data of p , whileppThe data of p is equal to the new data, so as to achieve a "forward interpolation" effect.// 指定结点的前插操作 O(1) bool inserPriorNode(LNode *p, int 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; }
c. delete
- The leading node is deleted in bit order:Average time complexity O ( n ) O(n)O ( n )
// 带头节点按位序删除 bool listDelete_h(linkList &L, int i, int &e) { if (i < 1) return false; LNode* p = L; int j = 0; while (p!=NULL && j<i-1) { // 将p指到第i-1个节点 p = p->next; j++; } if (p == NULL || p->next == NULL) // 表示第i-1或第i个节点不存在 return false; LNode *q = p->next; e = q->data; p->next = q->next; free(q); return true; }
- Specified node deletion:Time complexity O ( 1 ) O(1)O ( 1 ) version (stealing method)
bool deleteNode(LNode *p) { if (p == NULL || p->next == NULL) // 这种方法存在缺陷 // 当删除的结点位最后一个结点时,则只能从表头结点开始寻找p的前驱 return false; LNode *q = p->next; p->data = q->data; p->next = q->next; free(q); return true; }
d. Find
- Bitwise search of the leading node:Average time complexity O ( n ) O(n)O ( n )
LNode * getElem(linkList L, int i) { if (i < 1) return NULL; LNode *p = L; int j = 0; while (p!=NULL && j<i) { p = p->next; j++; } return p; }
- Lookup by value with head node:Average time complexity O ( n ) O(n)O ( n )
LNode * locateElem(linkList L, int e) { LNode *p = L->next; while (p != NULL && p->data != e) p = p->next; return p; }
- Find the table length of the leading node:Average time complexity O ( n ) O(n)O ( n )
int listLen(linkList L) { int len = 0; LNode *p = L; while (p->next != NULL) { p = p->next; len++; } return len; }
e. to establish
- The tail insertion method with the leading node establishes a singly linked list:
// 带头结点的尾插法建立单链表 linkList tailBuildLink_h(linkList &L) { int x; L = (linkList)malloc(sizeof(LNode)); LNode *s, *r = L; scanf("%d", &x); while (x != 999) { s = (LNode *)malloc(sizeof(LNode)); s->data = x; r->next = s; r = s; scanf("%d", &x); } r->next = NULL; return L; }
- The tail insertion method with tail nodes creates a singly linked list:
linkList headBuildLink_h(linkList &L) { int x; L = (linkList)malloc(sizeof(LNode)); L->next = NULL; LNode *s; scanf("%d", &x); while (x != 999) { s = (LNode *)malloc(sizeof(LNode)); s->data = x; s->next = L->next; L->next = s; scanf("%d", &x); } return L; }
IV. Double Linked List
- Define the structure:
typedef struct dNode { int data; struct dNode *prior, *next; }dNode, *dLinkList;
- Initialize the doubly linked list:
bool initDLink(dLinkList &L) { L = (dLinkList)malloc(sizeof(dNode)); if (L == NULL) return false; L->prior = NULL; L->next = NULL; return true; }
- Empty:
bool emptyDLink(dLinkList &L) { return L->next == NULL; }
- Insert a node after the specified node:
bool insertNextNode(dNode *p, dNode *s) { if (p == NULL || s == NULL) return false; s->prior = p; s->next = p->next; if (p->next != NULL) p->next->prior = s; p->next = s; return true; }
- Delete the node after the specified node:
bool deleteNextNode(dNode *p) { if (p == NULL || p->next == NULL) return false; dNode *q = p->next; if (q->next != NULL) q->next->prior = p; p->next = q->next; free(q); return true; }
- Destroy the linked list:
void destroyList(dLinkList &L) { while (L->next != NULL) deleteNextNode(L); free(L); L = NULL; }
V. Circular linked list
a. Circular singly linked list
Circular singly linked list:next next of the tail nodeThe n e x t pointer points to the head node
Compared with the singly linked list: starting from one node, any other node can be found
- Circular singly linked list structure definition:
typedef struct clNode { int data; struct clNode *next; }clNode, *clList;
- Circular singly linked list initialization:
bool initCList(clList &L) { L = (clNode *)malloc(sizeof(clNode)); if (L == NULL) return false; L->next = L; return true; }
- Circular singly linked list judgment null operation:
bool emptyCList(clList L) { return L->next == L; }
- Determine whether the node p is the end node:
bool isTail(clList L, clNode *p) { return p->next == L; }
b. Circular double linked list
Circular double linked list:On the basis of the double linked list, the prior prior of the header nodep r i or points to the end node,the next nextn e x t points to the head node
- Structure definition:
typedef struct cdNode { int data; struct cdNode *prior, *next; }cdNode, *cdLinkList;
- initialization:
bool initCDLinkList(cdLinkList &L) { L = (cdNode *)malloc(sizeof(cdNode)); if (L == NULL) return false; L->prior = L; L->next = L; return true; }
- Empty Judgment/ Tail Judgment:
bool isEmpty(cdLinkList L) { return L->next == L; } bool isTail(cdLinkList L, cdNode *p) { return p->next == L; }
- Insert the s node after the p node:
bool insertNextNode(cdNode *p, cdNode *s) { if (p == NULL || s == NULL) return false; s->next = p->next; s->prior = p; p->next->prior = s; p->next = s; return true; }
- Delete the successor node of p node:
bool deleteNextNode(cdNode *p, cdNode *q) { if (p == NULL || q == NULL) return false; p->next = q->next; q->next->prior = p; free(q); return true; }
VI. Static linked list
Static linked list:Allocate a whole piece of contiguous memory space, and each node is centrally placed; each node contains two parts: data and a "pointer" pointing to the next node
- Define the structure:
#define maxSize 10
struct Node {
int data;
int next;
};
typedef struct Node sLinkList[maxSize];
- Briefly describe the basic operation implementation:
- Search : starting from the head node and traversing backwards
- The insertion order is iiThe node of i
: create a new empty node and store the data;
find thei − 1 i-1i−1 node;the next next
of the new nodeN e x t is modified toi − 1 i-1i−1 的 n e x t next n e x t
willi − 1 i-1i−1 nodenext nextN ex t is modified to the position of the new node - The deletion order is iiThe node of i
: start from the head node to find thei − 1 i-1i−1 node
modifyi − 1 i-1i−1 nodenext nextn e x t pointer
will be theiinext next of i nodesn e x t pointer is set to -2
VII. Comparison of sequenced list and linked list
sequence table | linked list | |
---|---|---|
create | Need to pre-allocate space, and it is not convenient to expand | Only need to allocate a head node, and it is easy to expand |
destroy | (Static array) The system automatically reclaims space (Dynamic array) requires manual free | Each node is free in turn |
additions and deletions | Need to move lots of elements O ( n ) O(n)O ( n ) | Just modify the pointer, but the lookup also takes O ( n ) O(n)O ( n ) |
look up | (bitwise search) O ( 1 ) O(1)O ( 1 ) ; (lookup by value)O ( log 2 n ) O(\log2n)O(log2n ) _ | Both require O ( n ) O(n)O ( n ) |