第2章 线性表
线性表是具有相同特性数据元素的一个有限序列,其可以是一个空表。可以是有序的,也可以是无序的。
2.1 结构体定义
// 定义一个整形常量
# define maxSize 100
// 顺序表结构体定义
// 第一种表示
typedef struct{
int data[maxSize];
int length;
}Sqlist;
// 更为常见的表示
int A[maxSize];
int n;
// 单链表结点定义
typedef struct LNode{
int data;
struct LNode* next;
}LNode;
// 双链表结点定义
typedef struct DLNode{
int data;
struct LNode* prior;
struct LNode* next;
}DLNode;
2.2 顺序表
- 基本操作
// 初始化
void initElem(Sqlist& L){
L.length = 0;
}
// 求指定位置 p 的元素
int initElem(Sqlist L, int p, int& e){
if(p < 0 || p > L.length - 1)
return 0;
e = L.data[p];
return 1;
}
// 查找第一个值等于 e 的元素
int findElem(Sqlist L, int e){
for(int i = 0; i < L.length; i++){
if(e == L.data[i]) return i;
}
return -1;
}
// p 位置插入元素 e
int insertElem(Sqlist& L, int p, int e){
if(p < 0 || p > L.length || L.length == maxSize)
for(int i = L.length-1; i >= p; i--){
L.data[i+1] = L.data[i];
}
L.data[p] = e;
L.length++;
return 1;
}
// 删除下标为 p 的元素
int deleteElem(Sqlist& L, int p, int& e){
if(p < 0 || p > L.length - 1) return 0;
e = L.data[p];
for(int i = p; i < L.length - 1; i++){
L.data[i] = L.data[i+1];
}
L.length--;
return 1;
}
- 例子
// 已知一个递增有序排列的顺序表,设计一个算法,使插入元素 x 后该顺序表仍然递增有序排列
// 返回第一个比 x 元素大的元素位置
int findElem(Sqlist& L, int x){
for(int i = 0; i < L.length; i++){
if(L.data[i] > x){
return i;
}
}
return i; // 若不存在此元素, 则 i 正好标记表尾位置
}
// 插入 x 元素
void insertElem(Sqlist& L, int x){
int p;
p = findElem(L, x);
for(int i = L.length - 1; i >= p; i--){
L.data[i+1] = L.data[i];
}
L.data[p] = x;
L.length++;
}
2.3 单链表
- 基本操作
// 数组 a 中存储 n 个元素,建立链表 C
// 头插法
void createListF(LNode*& C, int a[], int n){
LNode* s;
C = (LNode *)malloc(sizeof(LNode));
C -> next = NULL;
for(int i = 0; i < n; i++){
s = (LNode *)malloc(sizeof(LNode));
s -> data = a[i];
s -> next = C -> next;
C -> next = s;
}
}
// 尾插法
void createListR(LNode*& C, int a[], int n){
LNode* s, * r;
C = (LNode *)malloc(sizeof(LNode));
C -> next = NULL;
r = C;
for(int i = 0; i < n; i++){
s = (LNode *)malloc(sizeof(LNode));
s -> data = a[i];
r -> next = s;
r = s;
}
r -> next = NULL;
}
//删除 p 位置的结点
int deleteList(LNode*& C, int p, int& e){
if(p < 1 || p > L.length) return 0;
LNode* s = C;
for(int i = 0; i < p - 1; i++){
s = s -> next; //找到第 p-1个结点
}
if(s == NULL || s -> next == NULL) return 0;
LNode* r = s -> next;
e = r -> data;
s -> next = r -> next;
free(r);
return 1;
}
//删除值为 x 的结点
int findAndDelete(LNode*& C, int x){
LNode* p, * q;
p = C;
while(p -> next != NULL){
if(p -> next -> data == x){
break;
}
p = p -> next;
}
if(p -> next == NULL) return 0;
q = p -> next;
p -> next = q -> next;
free(q);
return 1;
}
- 例子
// A 和 B 是两个带头结点的单链表,元素递增有序
// 将 A 和 B 归并成一个按元素值 非递减 有序的链表 C
// 尾插法
void merge(LNode* A, LNode* B, LNode*& C){
LNode *p = A -> next;
LNode *q = B -> next;
C = A;
C -> next = NULL;
free(B);
LNode *s = C;
while(p && q){
if(p -> data <= q -> data){
s -> next = p -> next;
p = p -> next;
}
else{
s -> next = q -> next;
q = q -> next;
}
s = s -> next;
}
if(p){
s -> next = p;
}
if(q){
s -> next = q;
}
}
// 设计一个算法,将 A 和 B 归并成一个按元素值 递减 有序的链表 C
// 头插法
void merge(LNode* A, LNode* B, LNode*& C){
LNode *p = A -> next;
LNode *q = B -> next;
LNode *s;
C = A;
C -> next = NULL;
free(B);
while(p && q){
if(p -> data <= q -> data){
s = p;
p = p -> next;
s -> next = C -> next;
C -> next = s;
}
else{
s = q;
q = q -> next;
s -> next = C -> next;
C -> next = s;
}
}
while(p){
s = p;
p = p -> next;
s -> next = C -> next;
C -> next = s;
}
if(q){
s = q;
q = q -> next;
s -> next = C -> next;
C -> next = s;
}
}
2.4 双链表
基本操作
// 尾插法建立双链表
void createDListR(DLNode*& L, int a[], int n){
DLNode* s, * r;
L =(DLNode *)malloc(sizeof(DLNode));
L -> next = NULL;
L -> prior = NULL;
r = L;
for(int i = 0; i < n; i++){
s =(DLNode *)malloc(sizeof(DLNode));
s -> data = a[i];
r -> next = s;
s -> prior = r;
r = r -> next;
}
r -> next = NULL;
}
//查找第一个值为 x 的结点
DLNode* findNode(DLNode* C; int x){
DLNode* p = C;
while(p){
if(p -> data == x) break;
p = p -> next;
}
return p; //包含未找到时 p = NULL 的情况
}
//在 p 后插入 s
int insertDLNode(DLNode* p, DLNode* s){
if(!p || !s) return 0;
s -> next = p -> next;
s -> prior = p;
p -> next = s;
if(p -> next){
s -> next -> prior = s;
}
return 0;
}
//删除 p 的后继结点
int deleteDLNode(DLNode* p){
if(!p || p -> next == NULL) return 0;
DLNode* q = p -> next;
p -> next = q -> next;
if(q -> next){
q -> next -> prior = p;
}
free(q);
return 1;
}
2.5 循环链表
// p 为表尾结点的条件
p -> next == head;
2.6 逆置问题(408重要考点)
// 逆置线性表中的元素
for(int i = left,j = right; i < j; i++, j--){
int temp = 0;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
// 将长度为 n 的数组前端 k(k < n) 个元素逆序后移动到数组后端,其余元素位置无关紧要
void reverse(int a[], int left, int right, int k){
int temp = 0;
for(int i = left, j = right; i < j; i++, j--){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
// 将长度为 n 的数组前端 k(k < n) 个元素保持原序移动到数组后端,其余元素位置无关紧要
void moveToEnd(int a[], int left, int right, int k){
reverse(a, 0, k-1, k);
reverse(a, 0, n-1, k);
}
// 将数组中的元素循环左移 p(0 < p < n) 个位置
void moveP(int a[], int left, int right, int k){
reverse(a, 0, p - 1, p);
reverse(a, p, n - 1, n - p);
reverse(a, 0, n - 1, n);
}