数据结构-c++

news2024/12/25 6:32:13

数据结构

  • 链表
    • 设计链表
    • 1.进制转换
    • 2.顺序表逆置
    • 3.链表转置
    • 栈的实现
  • 队列
    • 队列实现
    • 1.逆置队列
  • 二叉树
    • 遍历顺序
    • 1.树的深度
    • 2.左右子树交换
    • 3.输出并求出非叶子节点个数
    • 1.邻接矩阵转换成临界表
    • 2.深度优先搜索
  • 查找
    • 折半查找算法
  • 排序
    • 快速排序

链表

设计链表

#include <iostream>
using namespace std;

struct linknode
{
	int val;
	linknode* next;
	linknode(int val):val(val),next(NULL){};
};
linknode* _dummyhead;// 这里定义的头结点 是一个虚拟头结点,而不是真正的链表头结点
int _size;//链表的大小

//初始化链表 
void init()
{
	_dummyhead=new linknode(0);
	_size=0;
}

//获取第index个节点的值 ,如果index是非法数值直接返回-1, 注意index是从0开始的,第0个节点就是头结点
int get(int index)
{
	if(index>=_size||index<0)
	{
		return -1;
	}
	linknode* cur=_dummyhead->next;
	while(index--)
	{
		cur=cur->next;
	}
	return cur->val;
}

 // 在链表最前面插入一个节点,插入完成后,新插入的节点为链表的新的头结点
void addh(int val)
{
	linknode *newnode=new linknode(val);
	newnode->next=_dummyhead->next;
	_dummyhead->next=newnode;
	_size++;
} 

// 在链表最后面添加一个节点
void adde(int val)
{
	linknode* newnode =new linknode(val);
	linknode* cur=_dummyhead;
	while(cur->next!=NULL)
	{
		cur=cur->next;
	}
	cur->next=newnode;
	_size++;
} 


// 在第index个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果index大于链表的长度,则返回空
// 如果index小于0,则在头部插入节点
void addi(int index,int val)
{
	if(index>_size)return;
	if(index<0)index=0;
	linknode* newnode=new linknode(val);
	linknode* cur=_dummyhead;
	while(index--)
	{
		cur=cur->next;
	} 
	newnode->next=cur->next;
	cur->next=newnode;
	_size++;
}

//删除第index个节点,如果index 大于等于链表的长度,直接return,注意index是从0开始的
void deletei(int index)
{
	if(index>=_size||index<0)
	{
		return ;
	}
	linknode* cur = _dummyhead;
    while (index--) 
	{
        cur = cur->next;
    }
	linknode* tmp=cur->next;
	cur->next=cur->next->next;
	delete tmp;
	tmp=NULL;
	_size--;
}

//打印链表 
void printlist()
{
	linknode* cur=_dummyhead;
	while(cur->next!=NULL)
	{
		cout<<cur->next->val<<" ";
		cur=cur->next;
	}
	cout<<endl;
}
int main()
{

	return 0;
}

1.进制转换

1.设计一个算法,用带头结点的单链表实现非负十进制整数转二进制数。

思路:通过头插法这样我们在进行进制转换时就不用reverse了

#include <iostream>
using namespace std;
struct linknode
{
    int digit;  // 存储二进制的每一位
    linknode* next;
    linknode(int digit) :digit(digit), next(NULL) {}
};
linknode* _dummyhead=new linknode(0);//虚拟头节点
// 十进制数转二进制数的函数
void transform(int n)
{
    if (n < 0)
    {
        cout << 0;
        return;
    }
    while (n>0)
    {
        int remainder = n % 2;//获取余数
        linknode* newnode = new linknode(remainder);
        newnode->next = _dummyhead->next;
        _dummyhead->next = newnode;
        n /= 2;
    }
}
// 输出链表的内容(即二进制位)
void print()
{
    linknode* cur = _dummyhead;
    while (cur->next !=NULL)
    {
        cur = cur->next;
        cout << cur->digit;
    }
}
int main()
{
    int n;
    cin >> n;
    transform(n);
    print();
    return 0;
}

2.顺序表逆置

2.设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为 O(1)。

#include <iostream>
using namespace std;
#define MAXLEN 100
typedef int datatype;
// 顺序表结构定义
struct seqlist 
{
    datatype data[MAXLEN];  // 存储顺序表的元素
    int Length;             // 顺序表的当前长度
};
// 逆置顺序表的函数
void reverseList(seqlist& L) 
{
    int left = 0;                // 左指针,指向顺序表的开始
    int right = L.Length - 1;    // 右指针,指向顺序表的末尾
    while (left < right) 
    {
        // 交换L.data[left]和L.data[right]
        swap(L.data[left], L.data[right]);
        // 移动指针
        left++;
        right--;
    }
}
// 打印顺序表的函数
void printList(const seqlist& L) 
{
    for (int i = 0; i < L.Length; i++) 
    {
        cout << L.data[i] << " ";
    }
    cout << endl;
}
int main() 
{
    seqlist L = { {1, 2, 3, 4, 5}, 5 };  // 顺序表元素为1, 2, 3, 4, 5,长度为5
    cout << "原顺序表:";
    printList(L);  // 输出原顺序表
    reverseList(L);  // 逆置顺序表
    cout << "逆置后的顺序表:";
    printList(L);  // 输出逆置后的顺序表
    return 0;
}

3.链表转置

思路
首先定义一个cur指针,指向虚拟头结点的下一个节点,再定义一个pre指针,初始化为null。

然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们_dummyhead->next = pre; 就可以了,pre指针就指向了新的头结点。

#include <iostream>
using namespace std;
struct linknode
{
    int val;  
    linknode* next;
    linknode(int val) :val(val), next(NULL) {}
};
linknode* _dummyhead = new linknode(0);//虚拟头节点
// 在链表尾插入节点
void adde(int val)
{
    linknode* newnode = new linknode(val);
    linknode* cur =_dummyhead;
    while (cur->next != NULL)
    {
        cur = cur->next;
    }
    cur->next = newnode;
    newnode->next = NULL;
}
void reverselist()
{
    linknode* cur = _dummyhead->next;
    linknode* temp; // 保存cur的下一个节点
    linknode* pre = NULL;
    while (cur!=NULL)
    {
        temp = cur->next;// 保存一下 cur的下一个节点,因为接下来要改变cur->next
        cur->next = pre;// 翻转操作
        // 更新pre 和 cur指针
        pre = cur; 
        cur = temp;
    }
    _dummyhead->next = pre;  // 将头结点的next指向反转后的链表头
}
// 打印链表
void print() 
{
    linknode* cur = _dummyhead;
    while (cur->next != NULL) 
    {
        cout << cur->next->val << " ";
        cur = cur->next;
    }
    cout << endl;
}
int main()
{
    adde(1);
    adde(2);
    adde(3);
    adde(4);
    adde(5);
    // 输出原链表
    cout << "原链表: ";
    print();
    // 逆置链表
    reverselist();
    // 输出逆置后的链表
    cout << "逆置后的链表: ";
    print();
    return 0;
}

栈的实现

#include <iostream>

using namespace std;


const int N = 100;
// 假设栈的初始化、入栈、出栈和栈空判断等基本操作已经实现

// 栈的结构定义
struct seqstack {
    int data[N];  // 栈的存储空间
    int top;        // 栈顶指针
};

// 初始化栈
void init(seqstack* s) {
    s->top = -1;
}

// 入栈操作
void push(seqstack* s, int x) {
    if (s->top < N) {  // 防止栈溢出
        s->top++;
        s->data[s->top] = x;
    }
}

// 出栈操作
bool pop(seqstack* s, int& x) {
    if (s->top == -1) return false;  // 栈为空,无法出栈
    x = s->data[s->top];
    s->top--;
    return true;
}

// 栈空判断
bool empty(seqstack* s) {
    return s->top == -1;
}

// 非负十进制整数转八进制数
void transform(int n) {
    seqstack s;
    init(&s);

    // 特殊情况:如果n为0,直接输出0
    if (n == 0) {
        cout << 0 << endl;
        return;
    }

    // 进行转换
    while (n > 0) {
        push(&s, n % 8);  // 余数入栈
        n = n / 8;        // 更新n为商
    }

    // 弹出栈内元素并输出,得到八进制数
    while (!empty(&s)) {
        int digit;
        pop(&s, digit);
        cout << digit;
    }
    cout << endl;
}

int main() {
    int decimalNum;
    cout << "请输入一个非负十进制整数: ";
    cin >> decimalNum;

    cout << "该整数的八进制表示为: ";
    transform(decimalNum);

    return 0;
}

队列

队列实现

#include <iostream>
using namespace std;

#define maxsize 50
typedef int datatype;

typedef struct {
    datatype data[maxsize];
    int front;
    int rear;
} sqqueue;

// 初始化队列
void initque(sqqueue &q) {
    q.rear = q.front = 0;
}

// 判断队列是否为空
bool isempty(sqqueue &q) {
    return q.front == q.rear;
}

// 入队操作
bool enqueue(sqqueue &q, datatype x) {
    if ((q.rear + 1) % maxsize == q.front) {
        return false; // 队列满
    }
    q.data[q.rear] = x;
    q.rear = (q.rear + 1) % maxsize;
    return true;
}

// 出队操作
bool dequeue(sqqueue &q, datatype &x) {
    if (isempty(q)) {
        return false; // 队列空
    }
    x = q.data[q.front];
    q.front = (q.front + 1) % maxsize;
    return true;
}

// 获取队列大小
int que_size(sqqueue &q) {
    return (q.rear + maxsize - q.front) % maxsize;
}

// 显示队列内容
void showqueue(sqqueue &q) {
    int p = q.front;
    if (isempty(q)) {
        cout << "队空" << endl;
        return;
    }
    while (p != q.rear) {
        cout << q.data[p] << " ";
        p = (p + 1) % maxsize;
    }
    cout << endl;
}

int main() {
    sqqueue Q;
    initque(Q);
    int n;
    cin >> n; // 输入命令的数量
    
    while (n--) {
        int command, x;
        cin >> command; // 输入命令类型

        switch (command) {
            case 1:  // 入队操作
                cin >> x;
                if (!enqueue(Q, x)) {
                    cout << "队列满" << endl;  // 队列满时输出提示
                }
                break;

            case 2:  // 出队操作
                if (dequeue(Q, x)) {
                    cout << x << endl;  // 输出出队的元素
                } else {
                    cout << "no" << endl;  // 队列为空时输出提示
                }
                break;

            case 3:  // 查询队列大小
                cout << que_size(Q) << endl;
                break;
        }
    }
    return 0;
}

1.逆置队列

#include <iostream>
#include <stack>

using namespace std;

#define MAXSIZe 50  // 队列最大容量

// 队列的定义
typedef struct {
    int data[MAXSIZe];
    int front, rear;
} Queue;

// 栈的定义
typedef stack<int> Stack;

// 初始化队列
void init(Queue& q) {
    q.front = q.rear = 0;
}

// 判断队列是否为空
bool isempty(Queue& q) {
    return q.front == q.rear;
}

// 判断队列是否满
bool isfull(Queue& q) {
    return (q.rear + 1) % MAXSIZe == q.front;
}

// 入队
bool enqueue(Queue& q, int value) {
    if (isfull(q)) {
        return false;  // 队列满
    }
    q.data[q.rear] = value;
    q.rear = (q.rear + 1) % MAXSIZe;
    return true;
}

// 出队
bool dequeue(Queue& q, int& value) {
    if (isempty(q)) {
        return false;  // 队列空
    }
    value = q.data[q.front];
    q.front = (q.front + 1) % MAXSIZe;
    return true;
}

// 获取队列大小
int queuesize(Queue& q) {
    return (q.rear - q.front + MAXSIZe) % MAXSIZe;
}

// 显示队列
void showQueue(Queue& q) {
    if (isempty(q)) {
        cout << "队列为空" << endl;
        return;
    }
    int i = q.front;
    while (i != q.rear) {
        cout << q.data[i] << " ";
        i = (i + 1) % MAXSIZe;
    }
    cout << endl;
}

// 逆置队列
void reversequeue(Queue& q) {
    Stack s;
    int temp;

    // Step 1: 将队列中的所有元素压入栈
    while (!isempty(q)) {
        dequeue(q, temp);
        s.push(temp);
    }

    // Step 2: 将栈中的元素重新入队
    while (!s.empty()) {
        enqueue(q, s.top());
        s.pop();
    }
}

int main() {
    Queue q;
    init(q);

    // 向队列中添加元素
    enqueue(q, 1);
    enqueue(q, 2);
    enqueue(q, 3);
    enqueue(q, 4);
    enqueue(q, 5);

    // 显示队列
    cout << "原队列: ";
    showQueue(q);

    // 逆置队列
    reversequeue(q);

    // 显示逆置后的队列
    cout << "逆置后的队列: ";
    showQueue(q);

    return 0;
}

二叉树

遍历顺序

#include <iostream>
#include <queue>
using namespace std;

struct treenode 
{
    int val;
    treenode* left;
    treenode* right;
    treenode(int x) : val(x), left(NULL), right(NULL) {}
};

void preorder(treenode* cur)//前序遍历
{
    if (cur == NULL)return;
    cout << cur->val;
    preorder(cur->left);
    preorder(cur->right);
}

void inorder(treenode* cur)//中序遍历
{
    if (cur == NULL) return;
    inorder(cur->left);
    cout << cur->val;
    inorder(cur->right);
}

void postorder(treenode* cur)//后序遍历
{
    if (cur == NULL)return;
    postorder(cur->left);
    postorder(cur->right);
    cout << cur->val;
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root) 
{
    if (root == NULL) return;

    queue<treenode*> q;  // 创建一个队列
    q.push(root);  // 将根节点入队

    while (!q.empty()) {
        treenode* cur = q.front();  // 访问队头元素
        q.pop();  // 出队
        cout << cur->val << " ";  // 访问节点

        // 将左子节点和右子节点入队
        if (cur->left) q.push(cur->left);
        if (cur->right) q.push(cur->right);
    }
}

int main()
{

    return 0;
}


1.树的深度

编写一个递归算法,实现的功能是:求二叉树的深度并返回。

有如下二叉树的存储结构:
typedef struct tnode
{
   DataType   data;   //结点数据域 
   struct  tnode  *lchild,*rchild; //左右孩子指针
}BTree; 
该函数原型说明为:int TreeDepth(BTree *T); //T是二叉树

函数

// 递归函数:计算二叉树的深度
int treeDepth(BTree *T) {
    if (T == NULL) {
        return 0;  // 空树的深度是 0
    }

    // 递归计算左子树和右子树的深度
    int leftDepth = treeDepth(T->lchild);
    int rightDepth = treeDepth(T->rchild);

    // 返回左右子树深度的较大值加 1
    return max(leftDepth, rightDepth) + 1;
}

完整代码

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

struct treenode
{
	int val;
	treenode* left;
	treenode* right;
	treenode(int x):val(x), left(NULL), right(NULL) {}
};
void preorder(treenode* cur)//前序遍历
{
	if (cur == NULL)return;
	cout << cur->val;
	preorder(cur->left);
	preorder(cur->right);
}

void inorder(treenode* cur)//中序遍历
{
	if (cur == NULL)return;
	inorder(cur->left);
	cout << cur->val;
	inorder(cur->right);
}

void postorder(treenode* cur)//后序遍历
{
	if (cur == NULL)return;
	postorder(cur->left);
	postorder(cur->right);
	cout << cur->val;
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root)
{
	if (root == NULL)
	{
		return;
	}
	queue<treenode*> q;
	q.push(root);

	while (!q.empty())
	{
		treenode* cur = q.front();
		q.pop();
		cout << cur->val << " ";

		if (cur->left)q.push(cur->left);
		if (cur->right)q.push(cur->right);
	}
}

int treedepth(treenode* root)
{
	
	if (root == NULL)return 0;// 空树的深度是 0

	// 递归计算左子树和右子树的深度
	int leftdepth = treedepth(root->left);
	int rightdepth = treedepth(root->right);

	// 返回左右子树深度的较大值加 1
	return max(leftdepth, rightdepth) + 1;
}
int main()
{
	// 创建一个简单的二叉树
	//         1
	//       /   \
    //      2     3
	//     / \   / \
    //    4   5 6   7
	treenode* root = new treenode(1);
	root->left = new treenode(2);
	root->right = new treenode(3);
	root->left->left = new treenode(4);
	root->left->right = new treenode(5);
	root->right->left = new treenode(6);
	root->right->right = new treenode(7);

	cout << "层序遍历的结果为: ";
	levelOrder(root);
	cout << endl;

	cout << "树的深度是:" << treedepth(root);
	
	return 0;
}

2.左右子树交换

编写一个递归算法,实现的功能是:将二叉树中的每一个结点的左子树和右子树互换。

有如下二叉树的存储结构:
typedef struct tnode
{
   DataType   data;   //结点数据域 
   struct  tnode  *lchild,*rchild; //左右孩子指针
}BTree; 
该函数原型说明为:void exchange(BTree *T);

函数

// 递归函数:交换二叉树的每个节点的左右子树
void exchange(BTree *T) {
    if (T == NULL) {
        return;  // 如果节点为空,直接返回
    }

    // 交换当前节点的左右子树
    BTree *temp = T->lchild;
    T->lchild = T->rchild;
    T->rchild = temp;

    // 递归交换左右子树
    exchange(T->lchild);
    exchange(T->rchild);
}

完整代码

#include <iostream>
#include <queue>
using namespace std;

struct treenode
{
	int val;
	treenode* left;
	treenode* right;
	treenode(int x):val(x), left(NULL), right(NULL) {}
};
void preorder(treenode* cur)//前序遍历
{
	if (cur == NULL)return;
	cout << cur->val;
	preorder(cur->left);
	preorder(cur->right);
}

void inorder(treenode* cur)//中序遍历
{
	if (cur == NULL)return;
	inorder(cur->left);
	cout << cur->val;
	inorder(cur->right);
}

void postorder(treenode* cur)//后序遍历
{
	if (cur == NULL)return;
	postorder(cur->left);
	postorder(cur->right);
	cout << cur->val;
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root)
{
	if (root == NULL)
	{
		return;
	}
	queue<treenode*> q;
	q.push(root);

	while (!q.empty())
	{
		treenode* cur = q.front();
		q.pop();
		cout << cur->val << " ";

		if (cur->left)q.push(cur->left);
		if (cur->right)q.push(cur->right);
	}
}
void exchange(treenode* root)
{
	if (root == NULL)
		return;

	// 交换当前节点的左右子树
	treenode* temp = root->left;
	root->left = root->right;
	root->right = temp;

	// 递归交换左子树和右子树
	exchange(root->left);
	exchange(root->right);
}

int main()
{
	// 创建一个简单的二叉树
	//         1
	//       /   \
    //      2     3
	//     / \   / \
    //    4   5 6   7
	treenode* root = new treenode(1);
	root->left = new treenode(2);
	root->right = new treenode(3);
	root->left->left = new treenode(4);
	root->left->right = new treenode(5);
	root->right->left = new treenode(6);
	root->right->right = new treenode(7);

	cout << "层序遍历的结果为: ";
	levelOrder(root);
	cout << endl;

	// 交换左右子树
	exchange(root);

	cout << "交换左右子树后层序遍历的结果为: ";
	levelOrder(root);
	cout << endl;


	 //      1
	 //     / \
	 //    3   2
	 //   / \ / \
	 //  7  6 5  4

	return 0;
}

3.输出并求出非叶子节点个数

编写一个算法,实现的功能是:输出二叉树中所有非叶子结点,并求出非叶子结点的个数返回。

有如下二叉树的存储结构:
typedef char DataType ;
typedef struct tnode
{
   DataType   data;   //结点数据域 
   struct  tnode  *lchild,*rchild; //左右孩子指针
}BTree; 
该函数原型说明为:int Nonleafnum(BTree *T);  //T是二叉树


函数

// 递归函数:计算并输出二叉树中的所有非叶子节点
int Nonleafnum(BTree *T) {
    if (T == NULL) {
        return 0;  // 空树没有非叶子节点
    }

    int count = 0;

    // 判断当前节点是否是非叶子节点
    if (T->lchild != NULL || T->rchild != NULL) {
        cout << T->data << " ";  // 输出非叶子结点
        count = 1;  // 当前结点是非叶子节点,计数为 1
    }

    // 递归计算左子树和右子树的非叶子结点数
    count += Nonleafnum(T->lchild);
    count += Nonleafnum(T->rchild);

    return count;  // 返回非叶子结点的总数
}

完整代码

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;

struct treenode {
    int val;
    treenode* left;
    treenode* right;
    treenode(int x) : val(x), left(NULL), right(NULL) {}
};

// 前序遍历
void preorder(treenode* cur) {
    if (cur == NULL) return;
    cout << cur->val << " ";
    preorder(cur->left);
    preorder(cur->right);
}

// 中序遍历
void inorder(treenode* cur) {
    if (cur == NULL) return;
    inorder(cur->left);
    cout << cur->val << " ";
    inorder(cur->right);
}

// 后序遍历
void postorder(treenode* cur) {
    if (cur == NULL) return;
    postorder(cur->left);
    postorder(cur->right);
    cout << cur->val << " ";
}

// 层序遍历(广度优先遍历)
void levelOrder(treenode* root) {
    if (root == NULL) {
        return;
    }
    queue<treenode*> q;
    q.push(root);

    while (!q.empty()) {
        treenode* cur = q.front();
        q.pop();
        cout << cur->val << " ";

        if (cur->left) q.push(cur->left);
        if (cur->right) q.push(cur->right);
    }
}

// 求非叶子节点个数的函数
int Nonleafnum(treenode* T) {
    if (T == NULL) return 0;  // 空树没有非叶子节点

    int count = 0;

    // 判断当前节点是否是非叶子节点
    if (T->left != NULL || T->right != NULL) {
        count = 1;  // 当前节点是非叶子节点,计数为 1
    }

    // 递归计算左子树和右子树的非叶子节点数
    count += Nonleafnum(T->left);
    count += Nonleafnum(T->right);

    return count;  // 返回非叶子节点的总数
}

int main() {
    // 创建一个简单的二叉树
    //         1
    //       /   \
    //      2     3
    //     / \   / \
    //    4   5 6   7
    treenode* root = new treenode(1);
    root->left = new treenode(2);
    root->right = new treenode(3);
    root->left->left = new treenode(4);
    root->left->right = new treenode(5);
    root->right->left = new treenode(6);
    root->right->right = new treenode(7);

    // 层序遍历的结果
    cout << "层序遍历的结果为: ";
    levelOrder(root);
    cout << endl;

    // 输出非叶子节点个数
    int nonLeafCount = Nonleafnum(root);
    cout << "非叶子节点的个数是: " << nonLeafCount << endl;

    return 0;
}

1.邻接矩阵转换成临界表

1. 编写一个算法,实现的功能是:将无权无向图的邻接矩阵转换成邻接表。
有如下存储结构:
#define MAX 100 
typedef  struct 
{
	int  n,e;        //顶点数、边数 
	char  vexs[MAX];      //顶点数组 
	int  edges[MAX][MAX]; //边的邻接矩阵
}MGraph;    //图的邻接矩阵类型 

typedef char VertexType ;
typedef  struct  node   //定义边表结点 
{
	int adjvex;   //邻接点域 
	struct node  *next; //指向下一个邻接点的指针域 
}EdgeNode;    //边表类型
typedef  struct  vexnode //定义顶点表结点 
{
	VertexType  data;  //顶点域 
	EdgeNode *firstedge;  //指向第一条边结点的指针域 
}VHeadNode;    //邻接表结点类型 
typedef  struct
{
	VHeadNode  adjlist[MAX];  //邻接表结点数组 
	int  n,e;    //顶点数、边数 
}AdjList;    //图的邻接表类型 

该函数原型说明为:AdjList *MatToList(MGraph g)  
//g是邻接矩阵,返回一个邻接表

函数

// 将邻接矩阵转换为邻接表
AdjList* MatToList(MGraph g) 
{
    int i, j;

    // 动态分配邻接表内存
    AdjList* adjlist = new AdjList;
    adjlist->n = g.n;
    adjlist->e = g.e;

    // 初始化邻接表的顶点数据和边表
    for (i = 0; i < g.n; i++) 
    {
        adjlist->adjlist[i].data = g.vexs[i];
        adjlist->adjlist[i].firstedge = NULL; // 初始化每个顶点的边表为空
    }

    // 遍历邻接矩阵,填充邻接表
    for (i = 0; i < g.n; i++) 
    {
        for (j = i + 1; j < g.n; j++) 
        { // 修改此处,j从i+1开始,确保只插入一次边
            if (g.edges[i][j] == 1) 
            {
                // 插入的边从 i 到 j
                EdgeNode* newEdge = new EdgeNode;
                newEdge->adjvex = j;
                newEdge->next = adjlist->adjlist[i].firstedge;
                adjlist->adjlist[i].firstedge = newEdge;

                // 插入的边从 j 到 i
                EdgeNode* newEdgeRev = new EdgeNode;
                newEdgeRev->adjvex = i;
                newEdgeRev->next = adjlist->adjlist[j].firstedge;
                adjlist->adjlist[j].firstedge = newEdgeRev;
            }
        }
    }

    return adjlist;
}

完整代码

#include <iostream>
using namespace std;

#define MAX 100
typedef struct 
{
    int n, e;        // 顶点数、边数 
    char vexs[MAX];  // 顶点数组 
    int edges[MAX][MAX]; // 邻接矩阵
} MGraph; // 图的邻接矩阵类型 

typedef char VertexType;

typedef struct node 
{ // 定义边表结点 
    int adjvex;      // 邻接点域 
    struct node* next; // 指向下一个邻接点的指针域 
} EdgeNode; // 边表类型

typedef struct vexnode { // 定义顶点表结点 
    VertexType data;     // 顶点域 
    EdgeNode* firstedge; // 指向第一条边结点的指针域 
} VHeadNode; // 邻接表结点类型 

typedef struct 
{
    VHeadNode adjlist[MAX]; // 邻接表结点数组 
    int n, e; // 顶点数、边数 
} AdjList; // 图的邻接表类型 

// 将邻接矩阵转换为邻接表
AdjList* MatToList(MGraph g) 
{
    int i, j;

    // 动态分配邻接表内存
    AdjList* adjlist = new AdjList;
    adjlist->n = g.n;
    adjlist->e = g.e;

    // 初始化邻接表的顶点数据和边表
    for (i = 0; i < g.n; i++) 
    {
        adjlist->adjlist[i].data = g.vexs[i];
        adjlist->adjlist[i].firstedge = NULL; // 初始化每个顶点的边表为空
    }

    // 遍历邻接矩阵,填充邻接表
    for (i = 0; i < g.n; i++) 
    {
        for (j = i + 1; j < g.n; j++) 
        { // 修改此处,j从i+1开始,确保只插入一次边
            if (g.edges[i][j] == 1) 
            {
                // 插入的边从 i 到 j
                EdgeNode* newEdge = new EdgeNode;
                newEdge->adjvex = j;
                newEdge->next = adjlist->adjlist[i].firstedge;
                adjlist->adjlist[i].firstedge = newEdge;

                // 插入的边从 j 到 i
                EdgeNode* newEdgeRev = new EdgeNode;
                newEdgeRev->adjvex = i;
                newEdgeRev->next = adjlist->adjlist[j].firstedge;
                adjlist->adjlist[j].firstedge = newEdgeRev;
            }
        }
    }

    return adjlist;
}

// 打印邻接表
void printAdjList(AdjList* adjList) 
{
    for (int i = 0; i < adjList->n; i++) 
    {
        cout << adjList->adjlist[i].data << ": "; // 打印顶点
        EdgeNode* p = adjList->adjlist[i].firstedge;
        while (p != NULL) 
        {
            cout << adjList->adjlist[p->adjvex].data << " "; // 打印邻接点
            p = p->next;
        }
        cout << endl;
    }
}

int main() 
{
    MGraph g = 
    {
        5, 6,
        {'A', 'B', 'C', 'D', 'E'},
        {
            {0, 1, 0, 1, 0},
            {1, 0, 1, 0, 1},
            {0, 1, 0, 1, 1},
            {1, 0, 1, 0, 0},
            {0, 1, 1, 0, 0}
        }
    };

    // 调用函数转换邻接矩阵为邻接表
    AdjList* adjList = MatToList(g);

    // 打印邻接表
    printAdjList(adjList);

    // 释放内存
    for (int i = 0; i < adjList->n; i++) 
    {
        EdgeNode* p = adjList->adjlist[i].firstedge;
        while (p != NULL) 
        {
            EdgeNode* temp = p;
            p = p->next;
            delete temp; // 释放边节点内存
        }
    }
    delete adjList; // 释放邻接表内存

    return 0;
}
//因为是从头部插入进去的,所以输出是
//A: D B
//B : E C A
//C : E D B
//D : C A
//E : C B

2.深度优先搜索

编写一个算法,实现的功能是:从某个顶点开始深度优先搜索用邻接表存储表示的图。
有如下存储结构:
#define MAX 100 
typedef char VertexType ;
typedef  struct  node   //定义边表结点 
{
	int adjvex;   //邻接点域 
	struct node  *next; //指向下一个邻接点的指针域 
}EdgeNode;    //边表类型
typedef  struct  vexnode //定义顶点表结点 
{
	VertexType  data;  //顶点域 
	EdgeNode *firstedge;  //指向第一条边结点的指针域 
}VHeadNode;    //邻接表结点类型 
typedef  struct
{
	VHeadNode  adjlist[MAX];  //邻接表结点数组 
	int  n,e;    //顶点数、边数 
}AdjList;    //图的邻接表类型 
int visited[MAX];   //标志顶点是否被访问过的数组
该函数原型说明为:void DFS(AdjList *g,int vi); 
//从顶点vi开始深度优先搜索用邻接表存储的图g

函数

int visited[MAX]; // 标志顶点是否被访问过的数组

// 深度优先搜索
void DFS(AdjList* g, int vi) {
    // 访问当前顶点
    cout << "Visited " << g->adjlist[vi].data << endl;
    visited[vi] = 1;  // 标记当前顶点为已访问

    // 遍历当前顶点的邻接点
    EdgeNode* p = g->adjlist[vi].firstedge;
    while (p) {
        int w = p->adjvex;  // 邻接点索引
        if (!visited[w]) {  // 如果邻接点未访问
            DFS(g, w);  // 递归访问邻接点
        }
        p = p->next;  // 移动到下一个邻接点
    }
}

完整代码

#include <iostream>
#include <cstdlib>

using namespace std;

#define MAX 100

typedef char VertexType;

// 定义边表结点
struct EdgeNode 
{
    int adjvex;           // 邻接点
    EdgeNode* next;      // 指向下一个邻接点的指针
};

// 定义顶点表结点
struct VHeadNode 
{
    VertexType data;     // 顶点数据
    EdgeNode* firstedge; // 指向第一条边的指针
};

// 邻接表类型
struct AdjList 
{
    VHeadNode adjlist[MAX]; // 邻接表数组
    int n, e;               // 图的顶点数和边数
};

int visited[MAX]; // 标志顶点是否被访问过的数组

// 深度优先搜索
void DFS(AdjList* g, int vi) {
    // 访问当前顶点
    cout << "Visited " << g->adjlist[vi].data << endl;
    visited[vi] = 1;  // 标记当前顶点为已访问

    // 遍历当前顶点的邻接点
    EdgeNode* p = g->adjlist[vi].firstedge;
    while (p) {
        int w = p->adjvex;  // 邻接点索引
        if (!visited[w]) {  // 如果邻接点未访问
            DFS(g, w);  // 递归访问邻接点
        }
        p = p->next;  // 移动到下一个邻接点
    }
}

int main() 
{
    AdjList* g = new AdjList;  // 使用 new 创建图的邻接表

    cout << "请输入图的顶点数和边数(例如:5 6): ";
    cin >> g->n >> g->e;

    // 初始化访问标志数组
    for (int i = 0; i < MAX; i++) 
    {
        visited[i] = 0;
    }

    // 初始化图的顶点
    cout << "请输入图的每个顶点数据(例如:A B C D E): ";
    for (int i = 0; i < g->n; i++) 
    {
        cin >> g->adjlist[i].data;
        g->adjlist[i].firstedge = NULL;  // 初始化邻接表为空
    }

    // 输入图的边
    cout << "请输入图的每条边(格式:起点 终点): " << endl;
    for (int i = 0; i < g->e; i++) 
    {
        char start, end;
        cin >> start >> end;
        int startIndex = -1, endIndex = -1;

        // 查找起点和终点的索引
        for (int j = 0; j < g->n; j++) 
        {
            if (g->adjlist[j].data == start) 
            {
                startIndex = j;
            }
            if (g->adjlist[j].data == end) 
            {
                endIndex = j;
            }
        }

        // 处理起点到终点的边
        if (startIndex != -1 && endIndex != -1) 
        {
            // 创建边表节点
            EdgeNode* eNode = new EdgeNode;
            eNode->adjvex = endIndex;
            eNode->next = g->adjlist[startIndex].firstedge;
            g->adjlist[startIndex].firstedge = eNode;
        }
    }

    // 从顶点0(假设A)开始深度优先搜索
    cout << "从顶点 " << g->adjlist[0].data << " 开始深度优先搜索:" << endl;
    DFS(g, 0);

    // 释放动态分配的内存
    delete g;

    return 0;
}

查找

折半查找算法

 编写一个折半查找递归算法,实现功能是:递归折半查找关键字为k的位置并返回,若找到则返回相应位置,找不到则返回-1。
有如下折半查找的线性表结构:
typedef int KeyType;
typedef struct
{
	KeyType key;
}SearchL;
该函数原型说明为:int BSearch(SearchL r[],KeyType k,int low,int high); 
//r为线性表,k为查找关键字,low, high分别是低位下标和高位下标

函数

int BSearch(SearchL r[], KeyType k, int low, int high)
{
	if (low > high)
	{
		return -1;
	}
	int mid = (low+high) / 2;

	if (r[mid].key == k)
	{
		return mid;
	}
	else if (r[mid].key > k)
	{
		return BSearch(r, k, low, mid - 1);
	}
	else
	{
		return BSearch(r, k, mid + 1, high);
	}
}

完整代码

#include <iostream>
using namespace std;
const  int N = 100;
typedef int KeyType;

typedef struct
{
	KeyType key;

}SearchL;

int BSearch(SearchL r[], KeyType k, int low, int high)
{
	if (low > high)
	{
		return -1;
	}
	int mid = (low+high) / 2;

	if (r[mid].key == k)
	{
		return mid;
	}
	else if (r[mid].key > k)
	{
		return BSearch(r, k, low, mid - 1);
	}
	else
	{
		return BSearch(r, k, mid + 1, high);
	}
}

int main()
{
	int n;
	cout << "请输入线性表的大小: ";
	cin >> n;

	SearchL r[N];

	cout << "请输入线性中元素(按顺序输入):";
	for(int i=0;i<n;i++)
	{
		cin >> r[i].key;
	}

	KeyType k;
	cout << "请输入要查找的关键字:";
	cin >> k;

	int result = BSearch(r, k, 0, n - 1);

	if (result != -1)
	{
		cout << "关键字" << k << "的位置是:" << result<<endl;
	}
	else
	{
		cout << "关键字" << k << "不存在于线性表中"<<endl;
	}

	return 0;
}

排序

快速排序

 编写一个快速排序算法,实现功能是:用快速排序算法对排序表中的记录按关键字key进行从小到大排序。
有如下排序记录的存储结构:
typedef int KeyType;
typedef struct
{
	KeyType key;	
}LineList;
该函数原型说明为:void QuickSort(LineList r[],int low,int high); 
//r为排序表,low, high分别是低位下标和高位下标

函数

// 交换两个元素的位置
void Swap(LineList& a, LineList& b) {
    LineList temp = a;
    a = b;
    b = temp;
}

// 快速排序算法(将分区函数合并进来)
void QuickSort(LineList r[], int low, int high) {
    if (low < high) {
        // 选择基准元素,通常选择中间的元素
        int pivot = r[(low + high) / 2].key;
        int i = low - 1;  // i 表示小于基准元素的部分的最后一个元素的索引
        int j = high + 1;  // j 表示大于基准元素的部分的第一个元素的索引

        // 分区操作
        while (true) {
            // 寻找第一个大于或等于基准的元素
            do i++; while (r[i].key < pivot);

            // 寻找第一个小于或等于基准的元素
            do j--; while (r[j].key > pivot);

            // 如果 i < j, 则交换 r[i] 和 r[j]
            if (i < j) {
                Swap(r[i], r[j]);
            }
            else {
                // 否则返回 j 作为基准的位置
                break;
            }
        }

        // 递归地对基准元素左侧和右侧的部分进行快速排序
        QuickSort(r, low, j);
        QuickSort(r, j + 1, high);
    }
}

完整代码

#include <iostream>
using namespace std;

const int N = 100;
typedef int KeyType;

typedef struct {
    KeyType key;
} LineList;

// 交换两个元素的位置
void Swap(LineList& a, LineList& b) {
    LineList temp = a;
    a = b;
    b = temp;
}

// 快速排序算法(将分区函数合并进来)
void QuickSort(LineList r[], int low, int high) {
    if (low < high) {
        // 选择基准元素,通常选择中间的元素
        int pivot = r[(low + high) / 2].key;
        int i = low - 1;  // i 表示小于基准元素的部分的最后一个元素的索引
        int j = high + 1;  // j 表示大于基准元素的部分的第一个元素的索引

        // 分区操作
        while (true) {
            // 寻找第一个大于或等于基准的元素
            do i++; while (r[i].key < pivot);

            // 寻找第一个小于或等于基准的元素
            do j--; while (r[j].key > pivot);

            // 如果 i < j, 则交换 r[i] 和 r[j]
            if (i < j) {
                Swap(r[i], r[j]);
            }
            else {
                // 否则返回 j 作为基准的位置
                break;
            }
        }

        // 递归地对基准元素左侧和右侧的部分进行快速排序
        QuickSort(r, low, j);
        QuickSort(r, j + 1, high);
    }
}

// 输出排序后的数组
void PrintArray(LineList r[], int n) {
    for (int i = 0; i < n; i++) {
        cout << r[i].key << " ";
    }
    cout << endl;
}

int main() {
    int n;
    cout << "请输入排序表的大小: ";
    cin >> n;

    LineList r[N];  // 创建排序表

    cout << "请输入排序表中的元素(按顺序输入):";
    for (int i = 0; i < n; i++) {
        cin >> r[i].key;
    }

    // 调用快速排序
    QuickSort(r, 0, n - 1);

    // 输出排序后的数组
    cout << "排序后的元素为:";
    PrintArray(r, n);

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2265149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

渗透Vulnhub-DC-9靶机

本篇文章旨在为网络安全渗透测试行业靶机教学。通过阅读本文&#xff0c;读者将能够对渗透Vulnhub系列DC-6靶机有定的了解 一、信息收集阶段 DC-9靶场信息: DC-9靶场介绍&#xff1a; https://www.vulnhub.com/entry/dc-9,412/ DC-9靶场下载&#xff1a; https://download.vu…

【Linux系列】Shell 命令:`echo ““ > img.sh`及其应用

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

云图库平台(三)——后端用户模块开发

需求分析&#xff1a;对于用户模块而言&#xff0c;通常要实现下列功能&#xff1a; 用户注册&#xff1a;用户输入账号、密码、确认密码进行注册账号用户登录&#xff1a;用户通过输入账号、密码登录注册账号获取当前登录用户信息&#xff1a;即得到当前已登录用户的信息用户…

怎么设置电脑密码?Windows和Mac设置密码的方法

为电脑设置密码是保护个人信息安全的重要措施。无论是Windows系统还是MacOS系统&#xff0c;设置密码的步骤都相对简单&#xff0c;但需要根据不同的操作系统选择不同的方法。 一、Windows系统电脑密码设置 方法一&#xff1a;通过控制面板设置账户密码 点击桌面左下角的“开…

思考: 与人交际

前晚可能是因为我和某个曾经的同学&#xff08;我认为是朋友&#xff0c;但是它真的很讨厌&#xff0c;现在觉得它在PUA很多人&#xff09;发生了一件事情&#xff0c;现在没关系了&#xff0c;算是到此结束了&#xff0c;再也不见。 让我看清楚了人和人的交际需要什么&#xf…

突发!!!GitLab停止为中国大陆、港澳地区提供服务,60天内需迁移账号否则将被删除

GitLab停止为中国大陆、香港和澳门地区提供服务&#xff0c;要求用户在60天内迁移账号&#xff0c;否则将被删除。这一事件即将引起广泛的关注和讨论。以下是对该事件的扩展信息&#xff1a; 1. 背景介绍&#xff1a;GitLab是一家全球知名的软件开发平台&#xff0c;提供代码托…

vulnhub靶场-matrix-breakout-2-morpheus攻略(截止至获取shell)

扫描出ip为192.168.121.161 访问该ip&#xff0c;发现只是一个静态页面什么也没有 使用dir dirsearch 御剑都只能扫描到/robots.txt /server-status 两个页面&#xff0c;前者提示我们什么也没有&#xff0c;后面两个没有权限访问 扫描端口&#xff0c;存在81端口 访问&#x…

美股开户网:谷歌搜索迎“大动作”:推出AI模式切换选项应对竞争压力

谷歌的AI战略新举措 近日&#xff0c;硅谷权威媒体《The Information》报道了谷歌即将在其搜索引擎中推出一项全新的功能——“切换到AI模式”。这一新功能将为用户提供更加智能、对话式的回答&#xff0c;标志着谷歌对人工智能&#xff08;AI&#xff09;领域的进一步布局&am…

如何在window 使用 conda 环境下载大模型

最近开始学习 变形金刚&#xff0c;最大的问题就是 huggingface 无法访问&#xff0c;无论是翻墙还是通过本地镜像网站HF-Mirror&#xff0c;然后再通过git下载都很慢&#xff0c;影响学习进度&#xff0c;后面看了如下文章&#xff0c;Huggingface配置镜像_huggingface镜像-CS…

WebRTC学习二:WebRTC音视频数据采集

系列文章目录 第一篇 基于SRS 的 WebRTC 环境搭建 第二篇 基于SRS 实现RTSP接入与WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建 第四篇 WebRTC 学习一&#xff1a;获取音频和视频设备 第五篇 WebRTC学习二&#xff1a;WebRTC音视频数据采集 文章目录 系列文章…

内部知识库的未来展望:技术融合与用户体验的双重升级

在当今数字化飞速发展的时代&#xff0c;企业内部知识库作为知识管理的关键载体&#xff0c;正站在变革的十字路口&#xff0c;即将迎来技术融合与用户体验双重升级的崭新时代&#xff0c;这一系列变化将深度重塑企业知识管理的格局。 一、技术融合&#xff1a;开启知识管理新…

淘宝详情API接口怎么去使用,调用解析

淘宝开放平台提供了丰富的API接口&#xff0c;帮助开发者快速实现与淘宝的交互。其中&#xff0c;淘宝详情API是用于获取商品详情的重要接口之一。通过调用该接口&#xff0c;开发者可以获取到商品的详细信息&#xff0c;如价格、库存、描述等。本文将详细介绍如何调用淘宝详情…

框架程序设计-简答以及论述

目录 maven的pom作用&#xff1a; Pointcut("execution(*com.example.dome.*.*(……))") 缓存的作用&#xff0c;redis配置过程 Redis配置过程&#xff1a; SpringBoot缓存配置过程&#xff1a; AOP的五种增强注解&#xff1a; 论述题&#xff1a;包结构作用、…

【开源库 | xlsxio】C/C++读写.xlsx文件,xlsxio 在 Linux(Ubuntu18.04)的编译、交叉编译

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a; 2024-12-20 …

频繁拿下定点,华玉高性能中间件迈入商业化新阶段

伴随着智能驾驶渗透率的快速增长&#xff0c;中国基础软件市场开始进入黄金窗口期。 近日&#xff0c;华玉通软&#xff08;下称“华玉”&#xff09;正式获得某国内头部轨道交通产业集团的智能化中间件平台定点项目。这将是华玉在基础软件领域深耕和商业化发展过程中的又一重…

Mac电脑移动端抓包

*一、相关软件的安装* *1.下载地址* l Fiddler Everywhere 官网&#xff1a;https://www.telerik.com/download/fiddler-everywhere l Charles 官网&#xff1a;https://www.charlesproxy.com/ l Wireshark 官网&#xff1a;https://www.wireshark.org/download.html *…

Spring Boot 动态定时任务管理系统(轻量级实现)

Spring Boot项目中&#xff0c;实现动态增删和启停定时任务的功能对于许多应用场景来说至关重要。虽然Quartz框架是一个广泛使用的解决方案&#xff0c;但其复杂性和重量级特性可能使得项目变得臃肿和难以维护。为了解决这个问题&#xff0c;本项目旨在实现一个轻量级的定时任务…

提高保养效率:4S店预约系统的设计与开发

3.1可行性分析 开发者在进行开发系统之前&#xff0c;都需要进行可行性分析&#xff0c;保证该系统能够被成功开发出来。 3.1.1技术可行性 开发该4S店预约保养系统所采用的技术是vue和MYSQL数据库。计算机专业的学生在学校期间已经比较系统的学习了很多编程方面的知识&#xff…

网络下载ts流媒体

网络下载ts流媒体 查看下载排序合并 很多视频网站&#xff0c;尤其是微信小程序中的长视频无法获取到准确视频地址&#xff0c;只能抓取到.ts片段地址&#xff0c;下载后发现基本都是5~8秒时长。 例如&#xff1a; 我们需要将以上地址片段全部下载后排序后再合成新的长视频。 …

(叁)前端实现加密的方式:AES 加密(实现的两种方式)

前端实现加密&#xff1a; Ⅰ、AES 加密&#xff1a;1、使用 AES 加密前的准备工作&#xff1a;其一、安装 crypto-js &#xff1a;A、安装命令&#xff1a;B、成功安装后的截图&#xff1a; 2、实现 AES 加密的方式一&#xff1a;其一、在项目中创建 crypto.js 文件&#xff1…