顺序表是有序表。该说法是错误的。
顺序表指的是存储方式,与元素是否有序无关。
线性表为n(n≥0)个相同数据元素的有限序列,其特点为:
表示方法:L=(a₁, a₂, a₃, …, aₙ)
每个元素都有:
用一段连续的内存空间存储线性表中的元素。逻辑上相邻的元素,物理存储位置也相邻。
#define MAXSIZE 100
typedef struct {
ElemType elem[MAXSIZE];
int last; // 最后元素下标
} SeqList;
typedef struct {
ElemType *pElem;
int last;
int maxSize;
} SqList;
优点:
缺点:
算法一:双指针法(保持相对顺序)
void DeleteItems(SeqList *L, ElemType e) {
int i = -1, j = 0;
while (j <= L->last) {
if (L->elem[j] == e)
j++;
else {
L->elem[i+1] = L->elem[j];
j++; i++;
}
}
L->last = i;
}
算法二:两头夹击法(不保持相对顺序)
void DeleteItems(SeqList *L, ElemType e) {
int i = 0, j = L->last;
while (i <= j) {
while (i <= j && L->elem[i] != e) i++;
while (i <= j && L->elem[j] == e) j--;
if (i < j) {
L->elem[i] = L->elem[j];
i++; j--;
}
}
L->last = i - 1;
}
void DeleteRepeatItem(SeqList *L) {
int i = 0, j = 1;
while (j <= L->last) {
if (L->elem[i] == L->elem[j])
j++;
else {
L->elem[i+1] = L->elem[j];
i++; j++;
}
}
L->last = i;
}
void DelrepeatElem(SeqList *L) {
int *tmp = (int*)malloc(sizeof(int) * 1001);
int i = 0, j = 0, x;
memset(tmp, 0, 1001 * sizeof(int));
while (j <= L->last) {
x = L->elem[j];
if (tmp[x] == 1)
j++; // 重复出现,舍弃
else { // 第一次出现,保留
tmp[x] = 1;
L->elem[i] = L->elem[j];
i++; j++;
}
}
L->last = i - 1;
free(tmp);
}
int Majority(int A[], int n) {
int i, count = 1;
int majorNum = A[1];
// 第一阶段:找候选主元素
for (i = 2; i <= n; i++) {
if (A[i] == majorNum)
count++;
else {
if (count > 0)
count--;
else {
majorNum = A[i];
count = 1;
}
}
}
// 第二阶段:验证是否为真正的主元素
count = 0;
for (i = 1; i <= n; i++)
if (A[i] == majorNum) count++;
if (count > n / 2)
return majorNum;
else
return 0;
}
void pairNum(int a[], int n, int x) {
// 先排序(假设已排序)
int i = 0, j = n - 1;
bool found = false;
while (i < j) {
if (a[i] + a[j] == x) {
found = true;
cout << a[i] << " " << a[j] << endl;
i++; j--;
}
else if (a[i] + a[j] > x)
j--; // 和太大
else
i++; // 和太小
}
if (!found)
cout << "不存在!" << endl;
}
void findCommonElem(int A[], int B[], int C[], int n) {
int i = 0, j = 0, k = 0;
while (i < n && j < n && k < n) {
if (A[i] == B[j] && B[j] == C[k]) {
cout << A[i] << endl;
i++; j++; k++;
}
else {
int minVal = min(A[i], min(B[j], C[k]));
if (A[i] == minVal) i++;
if (B[j] == minVal) j++;
if (C[k] == minVal) k++;
}
}
}
int findMinDist(int s1[], int s2[], int s3[], int n1, int n2, int n3) {
int min_dist = INT_MAX;
int dist;
int i = 0, j = 0, k = 0;
while (i < n1 && j < n2 && k < n3) {
dist = abs(s1[i] - s2[j]) + abs(s2[j] - s3[k]) + abs(s3[k] - s1[i]);
if (dist < min_dist)
min_dist = dist;
// 移动指向最小元素的指针
if (s1[i] <= s2[j] && s1[i] <= s3[k]) i++;
else if (s2[j] <= s1[i] && s2[j] <= s3[k]) j++;
else k++;
}
return min_dist;
}
void AdjustSqlist(SeqList *L) {
int i = 0, j = L->last;
int temp;
while (i < j) {
while (i < j && L->elem[i] % 2 != 0) i++; // 找偶数
while (i < j && L->elem[j] % 2 == 0) j--; // 找奇数
if (i < j) {
temp = L->elem[i];
L->elem[i] = L->elem[j];
L->elem[j] = temp;
}
}
}
线性表中的元素在内存空间中的位置不一定连续。为了维系元素的逻辑关系,需要额外的指针域(next)记录下一个元素的位置。
typedef struct Node {
ElemType data;
struct Node *next;
} Node, *LinkList;
优点:
缺点:
插入操作:
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
删除操作:
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
Node *midNode(LinkList L) {
Node *fast, *slow;
fast = slow = L;
if (L->next == NULL) return NULL;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
void ReverseList(LinkList L) {
Node *p, *q;
p = L->next;
L->next = NULL;
while (p != NULL) {
q = p->next;
p->next = L->next;
L->next = p;
p = q;
}
}
void DelData(LinkList L, ElemType mink, ElemType maxk) {
Node *p = L->next, *pre = L, *temp;
// 找到开始删除的位置
while (p && p->data <= mink) {
pre = p;
p = p->next;
}
// 删除范围内的元素
while (p && p->data < maxk) {
temp = p->next;
free(p);
p = temp;
}
pre->next = p;
}
void ReversePrint(LinkList L) {
if (L == NULL) return;
if (L->next != NULL)
ReversePrint(L->next);
printf("%d ", L->data);
}
Node *FindKthToTail(LinkList L, int k) {
Node *fast = L, *slow = L;
// 快指针先走k步
for (int i = 0; i < k && fast != NULL; i++) {
fast = fast->next;
}
if (fast == NULL) return NULL; // k超出链表长度
// 快慢指针同时移动
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
return slow;
}
void delSame(LinkList L) {
int A[5001] = {0};
Node *pre, *p;
pre = L;
p = L->next;
while (p) {
int k = abs(p->data);
if (A[k] == 0) { // 第一次出现
A[k] = 1;
pre = p;
p = p->next;
}
else { // 已经出现过,删除该结点
pre->next = p->next;
free(p);
p = pre->next;
}
}
}
void specialReverse(LinkList L) {
Node *mid;
if (L->next == NULL) return;
mid = midNode(L); // 获取中间结点
// 逆置后半段
Node *p = mid->next, *tmp;
mid->next = NULL;
while (p) {
tmp = p->next;
p->next = mid->next;
mid->next = p;
p = tmp;
}
// 交替插入
p = L->next; // 前半段指针
Node *q = mid->next; // 后半段指针
mid->next = NULL;
while (q != NULL) {
tmp = q->next;
q->next = p->next;
p->next = q;
q = tmp;
p = p->next->next;
}
}
LinkList reverseKGroup(LinkList head, int k) {
if (head == NULL || head->next == NULL) return head;
// 计算链表长度
int len = 0;
Node *p = head->next;
while (p) {
len++;
p = p->next;
}
int groups = len / k; // 需要翻转的组数
Node *prev = head;
Node *curr = head->next;
for (int i = 0; i < groups; i++) {
Node *groupStart = curr;
// 翻转k个结点
for (int j = 0; j < k; j++) {
Node *next = curr->next;
curr->next = prev->next;
prev->next = curr;
curr = next;
}
groupStart->next = curr;
prev = groupStart;
}
return head;
}
优点:
缺点:
优点:
缺点:
根据以下因素选择合适的存储结构:
题目:顺序表L=(a₁,a₂,a₃,…aₙ,b₁,b₂,b₃,…,bₘ),n≠m。编写算法将其调整为L=(b₁,b₂,b₃,…,bₘ,a₁,a₂,a₃,…aₙ)
算法1:
算法2:
题目:给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数。
算法思想:
题目:某循环单链表(尾元素的指针域可指向链表中的任意一结点),编写算法求循环结点。
算法思想:使用快慢指针
在408考研中,算法设计要求: